From 99486032e13a05dbbb743d8ed38c95b366894c16 Mon Sep 17 00:00:00 2001 From: Britt Park Date: Wed, 8 Nov 2006 05:17:40 +0000 Subject: [PATCH] Humongous merge. It is incomplete, however; faces-config-navigation.xml and ClientConfigElement were both beyond me, and are just the raw conflict merge data. If Kev can't figure out how they should go together by tomorrow AM (for me) I'll dig back in. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@4306 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../extension/web-client-rm-custom.xml.sample | 171 + config/alfresco/messages/webclient.properties | 11 +- .../web-client-application-context.xml | 1 + config/alfresco/web-client-config-actions.xml | 2 +- .../alfresco/web-client-config-properties.xml | 175 +- config/alfresco/web-client-config.xml | 20 +- .../evaluator/CancelWorkflowEvaluator.java | 48 +- .../servlet/BaseTemplateContentServlet.java | 305 ++ .../servlet/GuestTemplateContentServlet.java | 188 + .../app/servlet/JBPMProcessImageServlet.java | 65 + .../app/servlet/TemplateContentServlet.java | 235 +- .../command/ApproveWorkflowCommand.java | 2 +- .../command/RejectWorkflowCommand.java | 2 +- .../alfresco/web/bean/BaseDetailsBean.java | 1 + .../web/bean/CheckinCheckoutBean.java | 2101 +++++----- .../org/alfresco/web/bean/SearchContext.java | 145 +- .../alfresco/web/bean/SpaceDetailsBean.java | 5 +- .../web/bean/dialog/DialogManager.java | 6 +- .../alfresco/web/bean/repository/Node.java | 2 +- .../web/bean/repository/TransientNode.java | 86 +- .../web/bean/workflow/ManageTaskDialog.java | 6 +- .../bean/workflow/StartWorkflowWizard.java | 2 +- .../web/bean/workflow/WorkflowBean.java | 183 +- .../bean/workflow/WorkflowConsoleBean.java | 184 + .../web/bean/{ => workflow}/WorkflowUtil.java | 82 +- .../web/config/ClientConfigElement.java | 106 +- .../web/config/ClientElementReader.java | 9 + .../common/renderer/DatePickerRenderer.java | 4 - .../ui/repo/component/UIContentSelector.java | 21 +- .../property/BaseAssociationEditor.java | 24 + .../repo/component/property/UIProperty.java | 7 +- .../web/ui/repo/tag/JBPMProcessImageTag.java | 254 ++ .../org/alfresco/web/ui/repo/tag/PageTag.java | 2 +- source/web/WEB-INF/faces-config-beans.xml | 15 +- .../web/WEB-INF/faces-config-navigation.xml | 890 +++++ source/web/WEB-INF/faces-config-repo.xml | 233 ++ source/web/WEB-INF/repo.tld | 3516 ++++++++--------- source/web/WEB-INF/web.xml | 10 + source/web/css/main.css | 22 - source/web/index.jsp | 3 +- source/web/jsp/admin/admin-console.jsp | 6 - source/web/jsp/admin/workflow-console.jsp | 102 + source/web/jsp/roles/manage-content-users.jsp | 3 +- source/web/jsp/roles/manage-invited-users.jsp | 3 +- .../jsp/workflow/tasks-completed-dashlet.jsp | 35 +- .../web/jsp/workflow/tasks-todo-dashlet.jsp | 41 +- 46 files changed, 5805 insertions(+), 3529 deletions(-) create mode 100644 config/alfresco/extension/web-client-rm-custom.xml.sample create mode 100644 source/java/org/alfresco/web/app/servlet/BaseTemplateContentServlet.java create mode 100644 source/java/org/alfresco/web/app/servlet/GuestTemplateContentServlet.java create mode 100644 source/java/org/alfresco/web/app/servlet/JBPMProcessImageServlet.java create mode 100644 source/java/org/alfresco/web/bean/workflow/WorkflowConsoleBean.java rename source/java/org/alfresco/web/bean/{ => workflow}/WorkflowUtil.java (64%) create mode 100644 source/java/org/alfresco/web/ui/repo/tag/JBPMProcessImageTag.java create mode 100644 source/web/jsp/admin/workflow-console.jsp diff --git a/config/alfresco/extension/web-client-rm-custom.xml.sample b/config/alfresco/extension/web-client-rm-custom.xml.sample new file mode 100644 index 0000000000..7854de078c --- /dev/null +++ b/config/alfresco/extension/web-client-rm-custom.xml.sample @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index 4dfab5ca5a..e0cd825e02 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -93,7 +93,6 @@ no_categories_applied_space=This space does not yet have any categories applied. has_following_categories_space=This space has the following categories applied... moved=moved copied=copied -document_action=The document will be {0} to ''{1}'' if the ''{2}'' action is taken. clipboard=Clipboard recent_spaces=Recent Spaces shortcuts=Shortcuts @@ -527,7 +526,6 @@ custom_view=Custom View view_links=Links not_inline_editable=This document is not inline editable. allow_inline_editing=Allow Inline Editing -not_in_workflow=This document is not part of any workflow. not_in_category=This document is not categorized. not_in_category_space=This space is not categorized. not_versioned=This document has no version history. @@ -1161,6 +1159,15 @@ admin_limited_license=Licensed: {0} license granted to {1} and limited to {3} da admin_unlimited_license=Licensed: {0} license granted to {1} and does not expire (issued on {2,date,short}). admin_invalid_license=Licensed: LICENSE INVALID - Alfresco Repository restricted to read-only capability. +# Workflow Console messages +title_workflow_console=Workflow Console +workflow_context=Context +workflow_command=Command (type help for help) +workflow_command_submit=Submit +workflow_last_command=Last command: +workflow_duration=Duration: +workflow_duration_ms=ms + # UI Page Titles title_about=About Alfresco title_login=Alfresco Web Client - Login diff --git a/config/alfresco/web-client-application-context.xml b/config/alfresco/web-client-application-context.xml index f43adab142..1a3c05c9b8 100644 --- a/config/alfresco/web-client-application-context.xml +++ b/config/alfresco/web-client-application-context.xml @@ -16,6 +16,7 @@ classpath:alfresco/web-client-config-wcm-actions.xml classpath:alfresco/web-client-config-workflow-actions.xml classpath:alfresco/extension/web-client-config-custom.xml + classpath:alfresco/extension/web-client-rm-custom.xml diff --git a/config/alfresco/web-client-config-actions.xml b/config/alfresco/web-client-config-actions.xml index cefde01e6a..2d3559591c 100644 --- a/config/alfresco/web-client-config-actions.xml +++ b/config/alfresco/web-client-config-actions.xml @@ -392,7 +392,7 @@ - ChangePermissions + CreateChildren advanced_space_wizard /images/icons/create_space.gif diff --git a/config/alfresco/web-client-config-properties.xml b/config/alfresco/web-client-config-properties.xml index 84c9cde9b5..01f56d7b85 100644 --- a/config/alfresco/web-client-config-properties.xml +++ b/config/alfresco/web-client-config-properties.xml @@ -26,30 +26,6 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + @@ -337,145 +313,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/alfresco/web-client-config.xml b/config/alfresco/web-client-config.xml index 9e5ffd48c4..6d4a92244a 100644 --- a/config/alfresco/web-client-config.xml +++ b/config/alfresco/web-client-config.xml @@ -46,6 +46,9 @@ -1 + + 500 + @@ -164,16 +167,6 @@ - - - - - - - - - - @@ -267,13 +260,6 @@ - - - - - - - diff --git a/source/java/org/alfresco/web/action/evaluator/CancelWorkflowEvaluator.java b/source/java/org/alfresco/web/action/evaluator/CancelWorkflowEvaluator.java index cdefed2495..86a7219a8c 100644 --- a/source/java/org/alfresco/web/action/evaluator/CancelWorkflowEvaluator.java +++ b/source/java/org/alfresco/web/action/evaluator/CancelWorkflowEvaluator.java @@ -21,7 +21,6 @@ import javax.faces.context.FacesContext; import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTask; import org.alfresco.util.ISO9075; import org.alfresco.web.action.ActionEvaluator; @@ -45,37 +44,28 @@ public class CancelWorkflowEvaluator implements ActionEvaluator public boolean evaluate(Node node) { boolean result = false; - - // get the id of the task - String taskId = (String)node.getProperties().get("id"); - if (taskId != null) + FacesContext context = FacesContext.getCurrentInstance(); + + // get the task from the node + WorkflowTask task = (WorkflowTask)node.getProperties().get("workflowTask"); + if (task != null) { - FacesContext context = FacesContext.getCurrentInstance(); - - // get the initiator of the workflow the task belongs to - WorkflowService workflowSvc = Repository.getServiceRegistry( - context).getWorkflowService(); - - WorkflowTask task = workflowSvc.getTaskById(taskId); - if (task != null) + NodeRef initiator = task.path.instance.initiator; + if (initiator != null) { - NodeRef initiator = task.path.instance.initiator; - if (initiator != null) + // find the current username + User user = Application.getCurrentUser(context); + String currentUserName = ISO9075.encode(user.getUserName()); + + // get the username of the initiator + NodeService nodeSvc = Repository.getServiceRegistry( + context).getNodeService(); + String userName = (String)nodeSvc.getProperty(initiator, ContentModel.PROP_USERNAME); + + // if the current user started the workflow allow the cancel action + if (currentUserName.equals(userName)) { - // find the current username - User user = Application.getCurrentUser(context); - String currentUserName = ISO9075.encode(user.getUserName()); - - // get the username of the initiator - NodeService nodeSvc = Repository.getServiceRegistry( - context).getNodeService(); - String userName = (String)nodeSvc.getProperty(initiator, ContentModel.PROP_USERNAME); - - // if the current user started the workflow allow the cancel action - if (currentUserName.equals(userName)) - { - result = true; - } + result = true; } } } diff --git a/source/java/org/alfresco/web/app/servlet/BaseTemplateContentServlet.java b/source/java/org/alfresco/web/app/servlet/BaseTemplateContentServlet.java new file mode 100644 index 0000000000..741d1d9948 --- /dev/null +++ b/source/java/org/alfresco/web/app/servlet/BaseTemplateContentServlet.java @@ -0,0 +1,305 @@ +/* + * 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. + */ +package org.alfresco.web.app.servlet; + +import java.io.IOException; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.transaction.UserTransaction; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.TemplateException; +import org.alfresco.service.cmr.repository.TemplateImageResolver; +import org.alfresco.service.cmr.repository.TemplateNode; +import org.alfresco.service.cmr.repository.TemplateService; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.web.ui.common.Utils; +import org.apache.commons.logging.Log; + +/** + * Base class for the template content servlets. Provides common + * processing for the request. + * + * @see org.alfresco.web.app.servlet.TemplateContentServlet + * @see org.alfresco.web.app.servlet.GuestTemplateContentServlet + * + * @author Kevin Roast + * @author gavinc + */ +public abstract class BaseTemplateContentServlet extends BaseServlet +{ + private static final String MIMETYPE_HTML = "text/html"; + + private static final long serialVersionUID = -4123407921997235977L; + + private static final String ARG_MIMETYPE = "mimetype"; + private static final String ARG_TEMPLATE_PATH = "templatePath"; + private static final String ARG_CONTEXT_PATH = "contextPath"; + + /** + * Gets the logger to use for this request. + *

+ * This will show all debug entries from this class as though they + * came from the subclass. + * + * @return The logger + */ + protected abstract Log getLogger(); + + /** + * Builds the FreeMarker model + * + * @param services Service Registry instance + * @param req Http request + * @param templateRef The node ref of the template to process + * @return The FreeMarker model + */ + protected abstract Map buildModel(ServiceRegistry services, + HttpServletRequest req, NodeRef templateRef); + + /** + * Processes the template request using the current context i.e. no + * authentication checks are made, it is presumed they have already + * been done. + * + * @param req The HTTP request + * @param res The HTTP response + * @param redirectToLogin Flag to determine whether to redirect to the login + * page if the user does not have the correct permissions + */ + protected void processTemplateRequest(HttpServletRequest req, HttpServletResponse res, + boolean redirectToLogin) throws ServletException, IOException + { + Log logger = getLogger(); + String uri = req.getRequestURI(); + + if (logger.isDebugEnabled()) + { + String queryString = req.getQueryString(); + logger.debug("Processing URL: " + uri + + ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : "")); + } + + uri = uri.substring(req.getContextPath().length()); + StringTokenizer t = new StringTokenizer(uri, "/"); + int tokenCount = t.countTokens(); + + t.nextToken(); // skip servlet name + + NodeRef nodeRef = null; + NodeRef templateRef = null; + + String contentPath = req.getParameter(ARG_CONTEXT_PATH); + if (contentPath != null && contentPath.length() != 0) + { + // process the name based path to resolve the NodeRef + PathRefInfo pathInfo = resolveNamePath(getServletContext(), contentPath); + + nodeRef = pathInfo.NodeRef; + } + else if (tokenCount > 3) + { + // get NodeRef to the content from the URL elements + StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken()); + nodeRef = new NodeRef(storeRef, t.nextToken()); + } + + // get NodeRef to the template if supplied + String templatePath = req.getParameter(ARG_TEMPLATE_PATH); + if (templatePath != null && templatePath.length() != 0) + { + // process the name based path to resolve the NodeRef + PathRefInfo pathInfo = resolveNamePath(getServletContext(), templatePath); + + templateRef = pathInfo.NodeRef; + } + else if (tokenCount >= 7) + { + StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken()); + templateRef = new NodeRef(storeRef, t.nextToken()); + } + + // if no context is specified, use the template itself + // TODO: should this default to something else? + if (nodeRef == null && templateRef != null) + { + nodeRef = templateRef; + } + + if (nodeRef == null) + { + throw new TemplateException("Not enough elements supplied in URL or no 'path' argument specified."); + } + + // get the services we need to retrieve the content + ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext()); + NodeService nodeService = serviceRegistry.getNodeService(); + TemplateService templateService = serviceRegistry.getTemplateService(); + PermissionService permissionService = serviceRegistry.getPermissionService(); + + // check that the user has at least READ access on any nodes - else redirect to the login page + if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED || + (templateRef != null && permissionService.hasPermission(templateRef, PermissionService.READ) == AccessStatus.DENIED)) + { + if (redirectToLogin) + { + if (logger.isDebugEnabled()) + logger.debug("Redirecting to login page..."); + + redirectToLoginPage(req, res, getServletContext()); + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Returning 403 Forbidden error..."); + + res.sendError(HttpServletResponse.SC_FORBIDDEN); + } + + return; + } + + String mimetype = MIMETYPE_HTML; + if (req.getParameter(ARG_MIMETYPE) != null) + { + mimetype = req.getParameter(ARG_MIMETYPE); + } + res.setContentType(mimetype); + + try + { + UserTransaction txn = null; + try + { + txn = serviceRegistry.getTransactionService().getUserTransaction(true); + txn.begin(); + + // if template not supplied, then use the default against the node + if (templateRef == null) + { + if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPLATABLE)) + { + templateRef = (NodeRef)nodeService.getProperty(nodeRef, ContentModel.PROP_TEMPLATE); + } + if (templateRef == null) + { + throw new TemplateException("Template reference not set against node or not supplied in URL."); + } + } + + // create the model - put the supplied noderef in as space/document as appropriate + Object model = getModel(serviceRegistry, req, templateRef, nodeRef); + + // process the template against the node content directly to the response output stream + // assuming the repo is capable of streaming in chunks, this should allow large files + // to be streamed directly to the browser response stream. + try + { + templateService.processTemplate( + null, + templateRef.toString(), + model, + res.getWriter()); + + // commit the transaction + txn.commit(); + } + catch (SocketException e) + { + if (e.getMessage().contains("ClientAbortException")) + { + // the client cut the connection - our mission was accomplished apart from a little error message + logger.error("Client aborted stream read:\n node: " + nodeRef + "\n template: " + templateRef); + try { if (txn != null) {txn.rollback();} } catch (Exception tex) {} + } + else + { + throw e; + } + } + } + catch (Throwable txnErr) + { + try { if (txn != null) {txn.rollback();} } catch (Exception tex) {} + throw txnErr; + } + } + catch (Throwable err) + { + throw new AlfrescoRuntimeException("Error during template servlet processing: " + err.getMessage(), err); + } + } + + /** + * Build the model that to process the template against. + *

+ * The model includes the usual template root objects such as 'companyhome', 'userhome', + * 'person' and also includes the node specified on the servlet URL as 'space' and 'document' + * + * @param services ServiceRegistry required for TemplateNode construction + * @param req Http request - for accessing Session and url args + * @param templateRef NodeRef of the template itself + * @param nodeRef NodeRef of the space/document to process template against + * + * @return an object model ready for executing template against + */ + @SuppressWarnings("unchecked") + private Object getModel(ServiceRegistry services, HttpServletRequest req, NodeRef templateRef, NodeRef nodeRef) + { + // build FreeMarker default model and merge + Map root = buildModel(services, req, templateRef); + + // put the current NodeRef in as "space" and "document" + TemplateNode node = new TemplateNode(nodeRef, services, this.imageResolver); + root.put("space", node); + root.put("document", node); + + // add URL arguments as a map called 'args' to the root of the model + Map args = new HashMap(8, 1.0f); + Enumeration names = req.getParameterNames(); + while (names.hasMoreElements()) + { + String name = (String)names.nextElement(); + args.put(name, req.getParameter(name)); + } + root.put("args", args); + + return root; + } + + /** Template Image resolver helper */ + private TemplateImageResolver imageResolver = new TemplateImageResolver() + { + public String resolveImagePathForName(String filename, boolean small) + { + return Utils.getFileTypeImage(getServletContext(), filename, small); + } + }; +} diff --git a/source/java/org/alfresco/web/app/servlet/GuestTemplateContentServlet.java b/source/java/org/alfresco/web/app/servlet/GuestTemplateContentServlet.java new file mode 100644 index 0000000000..6800dcacd5 --- /dev/null +++ b/source/java/org/alfresco/web/app/servlet/GuestTemplateContentServlet.java @@ -0,0 +1,188 @@ +/* + * 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. + */ +package org.alfresco.web.app.servlet; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.service.ServiceRegistry; +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.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.web.bean.repository.User; +import org.alfresco.web.ui.repo.component.template.DefaultModelHelper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +/** + * Servlet responsible for streaming content from a template processed against a node directly + * to the response stream. + *

+ * The URL to the servlet should be generated thus: + *

/alfresco/template/workspace/SpacesStore/0000-0000-0000-0000
+ * or + *
/alfresco/template/workspace/SpacesStore/0000-0000-0000-0000/workspace/SpacesStore/0000-0000-0000-0000
+ * or + *
/alfresco/template?templatePath=/Company%20Home/Data%20Dictionary/Presentation%20Templates/doc_info.ftl&contextPath=/Company%20Home/mydoc.txt
+ *

+ * The store protocol, followed by the store ID, followed by the content Node Id used to + * identify the node to execute the default template for. The second set of elements encode + * the store and node Id of the template to used if a default is not set or not requested. Instead + * of using NodeRef references to the template and context, path arguments can be used. The URL args + * of 'templatePath' and 'contextPath' can be used instead to specify name based encoded Paths to the + * template and its context. + *

+ * The URL may be followed by a 'mimetype' argument specifying the mimetype to return the result as + * on the stream. Otherwise it is assumed that HTML is the default response mimetype. + *

+ * Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication: + * ?ticket=1234567890 + *

+ * And/or also followed by the "?guest=true" argument to force guest access login for the URL. If the + * guest=true parameter is used the current session will be logged out and the guest user logged in. + * Therefore upon completion of this request the current user will be "guest". + *

+ * This servlet only accesses content available to the guest user. If the guest user does not + * have access to the requested a 401 Forbidden response is returned to the caller. + *

+ * This servlet does not effect the current session, therefore if guest access is required to a + * resource this servlet can be used without logging out the current user. + * + * @author gavinc + */ +public class GuestTemplateContentServlet extends BaseTemplateContentServlet +{ + private static final long serialVersionUID = -2510767849932627519L; + + private static final Log logger = LogFactory.getLog(GuestTemplateContentServlet.class); + + private static final String DEFAULT_URL = "/guestTemplate/{0}/{1}/{2}"; + private static final String TEMPLATE_URL = "/guestTemplate/{0}/{1}/{2}/{3}/{4}/{5}"; + + @Override + protected Log getLogger() + { + return logger; + } + + @Override + protected Map buildModel(ServiceRegistry services, HttpServletRequest req, + NodeRef templateRef) + { + // setup the guest user to pass to the build model helper method + AuthenticationService auth = (AuthenticationService)services.getAuthenticationService(); + PersonService personService = (PersonService)services.getPersonService(); + NodeService nodeService = (NodeService)services.getNodeService(); + + NodeRef guestRef = personService.getPerson(PermissionService.GUEST_AUTHORITY); + User guestUser = new User(PermissionService.GUEST_AUTHORITY, auth.getCurrentTicket(), guestRef); + NodeRef guestHomeRef = (NodeRef)nodeService.getProperty(guestRef, ContentModel.PROP_HOMEFOLDER); + if (nodeService.exists(guestHomeRef) == false) + { + throw new InvalidNodeRefException(guestHomeRef); + } + guestUser.setHomeSpaceId(guestHomeRef.getId()); + + // build the default model + return DefaultModelHelper.buildDefaultModel(services, guestUser, templateRef); + } + + /** + * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + protected void service(HttpServletRequest req, HttpServletResponse res) + throws ServletException, IOException + { + if (logger.isDebugEnabled()) + { + String queryString = req.getQueryString(); + logger.debug("Setting up guest access to URL: " + req.getRequestURI() + + ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : "")); + } + + TemplateContentWork tcw = new TemplateContentWork(req, res); + AuthenticationUtil.runAs(tcw, PermissionService.GUEST_AUTHORITY); + } + + /** + * Helper to generate a URL to process a template against a node. + *

+ * The result of the template is supplied returned as the response. + * + * @param nodeRef NodeRef of the content node to generate URL for (cannot be null) + * @param templateRef NodeRef of the template to process against, or null to use default + * + * @return URL to process the template + */ + public final static String generateURL(NodeRef nodeRef, NodeRef templateRef) + { + if (templateRef == null) + { + return MessageFormat.format(DEFAULT_URL, new Object[] { + nodeRef.getStoreRef().getProtocol(), + nodeRef.getStoreRef().getIdentifier(), + nodeRef.getId() } ); + } + else + { + return MessageFormat.format(TEMPLATE_URL, new Object[] { + nodeRef.getStoreRef().getProtocol(), + nodeRef.getStoreRef().getIdentifier(), + nodeRef.getId(), + templateRef.getStoreRef().getProtocol(), + templateRef.getStoreRef().getIdentifier(), + templateRef.getId()} ); + } + } + + /** + * Class to wrap the call to processTemplateRequest. + * + * @author gavinc + */ + public class TemplateContentWork implements RunAsWork + { + private HttpServletRequest req = null; + private HttpServletResponse res = null; + + public TemplateContentWork(HttpServletRequest req, HttpServletResponse res) + { + this.req = req; + this.res = res; + } + + public Object doWork() throws Exception + { + processTemplateRequest(this.req, this.res, false); + + return null; + } + } +} diff --git a/source/java/org/alfresco/web/app/servlet/JBPMProcessImageServlet.java b/source/java/org/alfresco/web/app/servlet/JBPMProcessImageServlet.java new file mode 100644 index 0000000000..fd4e895f5e --- /dev/null +++ b/source/java/org/alfresco/web/app/servlet/JBPMProcessImageServlet.java @@ -0,0 +1,65 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2005, JBoss Inc., and individual contributors as indicated + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This 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 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.alfresco.web.app.servlet; + +import java.io.IOException; +import java.io.OutputStream; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.jbpm.JbpmContext; +import org.jbpm.graph.def.ProcessDefinition; + + +// +// +// TODO: DC: Tidy up +// +// + + + + +public class JBPMProcessImageServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + long processDefinitionId = Long.parseLong( request.getParameter( "definitionId" ) ); + JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext(); + ProcessDefinition processDefinition = jbpmContext.getGraphSession().loadProcessDefinition(processDefinitionId); + byte[] bytes = processDefinition.getFileDefinition().getBytes("processimage.jpg"); + OutputStream out = response.getOutputStream(); + out.write(bytes); + out.flush(); + + // leave this in. it is in case we want to set the mime type later. + // get the mime type + // String contentType = URLConnection.getFileNameMap().getContentTypeFor( fileName ); + // set the content type (=mime type) + // response.setContentType( contentType ); + } +} diff --git a/source/java/org/alfresco/web/app/servlet/TemplateContentServlet.java b/source/java/org/alfresco/web/app/servlet/TemplateContentServlet.java index a728e7bc93..09effd521d 100644 --- a/source/java/org/alfresco/web/app/servlet/TemplateContentServlet.java +++ b/source/java/org/alfresco/web/app/servlet/TemplateContentServlet.java @@ -17,32 +17,16 @@ package org.alfresco.web.app.servlet; import java.io.IOException; -import java.net.SocketException; import java.text.MessageFormat; -import java.util.Enumeration; -import java.util.HashMap; import java.util.Map; -import java.util.StringTokenizer; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.transaction.UserTransaction; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.repository.TemplateException; -import org.alfresco.service.cmr.repository.TemplateImageResolver; -import org.alfresco.service.cmr.repository.TemplateNode; -import org.alfresco.service.cmr.repository.TemplateService; -import org.alfresco.service.cmr.security.AccessStatus; -import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.web.app.Application; -import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.repo.component.template.DefaultModelHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -71,24 +55,37 @@ import org.apache.commons.logging.LogFactory; * Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication: * ?ticket=1234567890 *

- * And/or also followed by the "?guest=true" argument to force guest access login for the URL. + * And/or also followed by the "?guest=true" argument to force guest access login for the URL. If the + * guest=true parameter is used the current session will be logged out and the guest user logged in. + * Therefore upon completion of this request the current user will be "guest". + *

+ * If the user attempting the request is not authorised to access the requested node the login page + * will be redirected to. * * @author Kevin Roast */ -public class TemplateContentServlet extends BaseServlet -{ - private static final String MIMETYPE_HTML = "text/html"; +public class TemplateContentServlet extends BaseTemplateContentServlet +{ + private static final long serialVersionUID = -2510767849932627519L; - private static final long serialVersionUID = -4123407921997235977L; - - private static Log logger = LogFactory.getLog(TemplateContentServlet.class); + private static final Log logger = LogFactory.getLog(TemplateContentServlet.class); private static final String DEFAULT_URL = "/template/{0}/{1}/{2}"; private static final String TEMPLATE_URL = "/template/{0}/{1}/{2}/{3}/{4}/{5}"; - private static final String ARG_MIMETYPE = "mimetype"; - private static final String ARG_TEMPLATE_PATH = "templatePath"; - private static final String ARG_CONTEXT_PATH = "contextPath"; + @Override + protected Log getLogger() + { + return logger; + } + + @Override + protected Map buildModel(ServiceRegistry services, HttpServletRequest req, + NodeRef templateRef) + { + return DefaultModelHelper.buildDefaultModel(services, + Application.getCurrentUser(req.getSession()), templateRef); + } /** * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) @@ -96,12 +93,10 @@ public class TemplateContentServlet extends BaseServlet protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { - String uri = req.getRequestURI(); - if (logger.isDebugEnabled()) { String queryString = req.getQueryString(); - logger.debug("Processing URL: " + uri + + logger.debug("Authenticating request to URL: " + req.getRequestURI() + ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : "")); } @@ -111,189 +106,9 @@ public class TemplateContentServlet extends BaseServlet return; } - uri = uri.substring(req.getContextPath().length()); - StringTokenizer t = new StringTokenizer(uri, "/"); - int tokenCount = t.countTokens(); - - t.nextToken(); // skip servlet name - - NodeRef nodeRef = null; - NodeRef templateRef = null; - - String contentPath = req.getParameter(ARG_CONTEXT_PATH); - if (contentPath != null && contentPath.length() != 0) - { - // process the name based path to resolve the NodeRef - PathRefInfo pathInfo = resolveNamePath(getServletContext(), contentPath); - - nodeRef = pathInfo.NodeRef; - } - else if (tokenCount > 3) - { - // get NodeRef to the content from the URL elements - StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken()); - nodeRef = new NodeRef(storeRef, t.nextToken()); - } - - // get NodeRef to the template if supplied - String templatePath = req.getParameter(ARG_TEMPLATE_PATH); - if (templatePath != null && templatePath.length() != 0) - { - // process the name based path to resolve the NodeRef - PathRefInfo pathInfo = resolveNamePath(getServletContext(), templatePath); - - templateRef = pathInfo.NodeRef; - } - else if (tokenCount >= 7) - { - StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken()); - templateRef = new NodeRef(storeRef, t.nextToken()); - } - - // if no context is specified, use the template itself - // TODO: should this default to something else? - if (nodeRef == null && templateRef != null) - { - nodeRef = templateRef; - } - - if (nodeRef == null) - { - throw new TemplateException("Not enough elements supplied in URL or no 'path' argument specified."); - } - - // get the services we need to retrieve the content - ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext()); - NodeService nodeService = serviceRegistry.getNodeService(); - TemplateService templateService = serviceRegistry.getTemplateService(); - PermissionService permissionService = serviceRegistry.getPermissionService(); - - // check that the user has at least READ access on any nodes - else redirect to the login page - if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED || - (templateRef != null && permissionService.hasPermission(templateRef, PermissionService.READ) == AccessStatus.DENIED)) - { - redirectToLoginPage(req, res, getServletContext()); - return; - } - - String mimetype = MIMETYPE_HTML; - if (req.getParameter(ARG_MIMETYPE) != null) - { - mimetype = req.getParameter(ARG_MIMETYPE); - } - res.setContentType(mimetype); - - try - { - UserTransaction txn = null; - try - { - txn = serviceRegistry.getTransactionService().getUserTransaction(true); - txn.begin(); - - // if template not supplied, then use the default against the node - if (templateRef == null) - { - if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPLATABLE)) - { - templateRef = (NodeRef)nodeService.getProperty(nodeRef, ContentModel.PROP_TEMPLATE); - } - if (templateRef == null) - { - throw new TemplateException("Template reference not set against node or not supplied in URL."); - } - } - - // create the model - put the supplied noderef in as space/document as appropriate - Object model = getModel(serviceRegistry, req, templateRef, nodeRef); - - // process the template against the node content directly to the response output stream - // assuming the repo is capable of streaming in chunks, this should allow large files - // to be streamed directly to the browser response stream. - try - { - templateService.processTemplate( - null, - templateRef.toString(), - model, - res.getWriter()); - - // commit the transaction - txn.commit(); - } - catch (SocketException e) - { - if (e.getMessage().contains("ClientAbortException")) - { - // the client cut the connection - our mission was accomplished apart from a little error message - logger.error("Client aborted stream read:\n node: " + nodeRef + "\n template: " + templateRef); - try { if (txn != null) {txn.rollback();} } catch (Exception tex) {} - } - else - { - throw e; - } - } - } - catch (Throwable txnErr) - { - try { if (txn != null) {txn.rollback();} } catch (Exception tex) {} - throw txnErr; - } - } - catch (Throwable err) - { - throw new AlfrescoRuntimeException("Error during template servlet processing: " + err.getMessage(), err); - } + processTemplateRequest(req, res, true); } - /** - * Build the model that to process the template against. - *

- * The model includes the usual template root objects such as 'companyhome', 'userhome', - * 'person' and also includes the node specified on the servlet URL as 'space' and 'document' - * - * @param services ServiceRegistry required for TemplateNode construction - * @param req Http request - for accessing Session and url args - * @param templateRef NodeRef of the template itself - * @param nodeRef NodeRef of the space/document to process template against - * - * @return an object model ready for executing template against - */ - @SuppressWarnings("unchecked") - private Object getModel(ServiceRegistry services, HttpServletRequest req, NodeRef templateRef, NodeRef nodeRef) - { - // build FreeMarker default model and merge - Map root = DefaultModelHelper.buildDefaultModel( - services, Application.getCurrentUser(req.getSession()), templateRef); - - // put the current NodeRef in as "space" and "document" - TemplateNode node = new TemplateNode(nodeRef, services, this.imageResolver); - root.put("space", node); - root.put("document", node); - - // add URL arguments as a map called 'args' to the root of the model - Map args = new HashMap(8, 1.0f); - Enumeration names = req.getParameterNames(); - while (names.hasMoreElements()) - { - String name = (String)names.nextElement(); - args.put(name, req.getParameter(name)); - } - root.put("args", args); - - return root; - } - - /** Template Image resolver helper */ - private TemplateImageResolver imageResolver = new TemplateImageResolver() - { - public String resolveImagePathForName(String filename, boolean small) - { - return Utils.getFileTypeImage(getServletContext(), filename, small); - } - }; - /** * Helper to generate a URL to process a template against a node. *

diff --git a/source/java/org/alfresco/web/app/servlet/command/ApproveWorkflowCommand.java b/source/java/org/alfresco/web/app/servlet/command/ApproveWorkflowCommand.java index 135da7aadf..1ffb92f8df 100644 --- a/source/java/org/alfresco/web/app/servlet/command/ApproveWorkflowCommand.java +++ b/source/java/org/alfresco/web/app/servlet/command/ApproveWorkflowCommand.java @@ -20,7 +20,7 @@ import java.util.Map; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.web.bean.WorkflowUtil; +import org.alfresco.web.bean.workflow.WorkflowUtil; /** * Approve Workflow command implementation diff --git a/source/java/org/alfresco/web/app/servlet/command/RejectWorkflowCommand.java b/source/java/org/alfresco/web/app/servlet/command/RejectWorkflowCommand.java index aee30ccb9b..2775f360fe 100644 --- a/source/java/org/alfresco/web/app/servlet/command/RejectWorkflowCommand.java +++ b/source/java/org/alfresco/web/app/servlet/command/RejectWorkflowCommand.java @@ -20,7 +20,7 @@ import java.util.Map; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.web.bean.WorkflowUtil; +import org.alfresco.web.bean.workflow.WorkflowUtil; /** * Reject Workflow command implementation diff --git a/source/java/org/alfresco/web/bean/BaseDetailsBean.java b/source/java/org/alfresco/web/bean/BaseDetailsBean.java index 09d0b7b6bb..c235d4aa2c 100644 --- a/source/java/org/alfresco/web/bean/BaseDetailsBean.java +++ b/source/java/org/alfresco/web/bean/BaseDetailsBean.java @@ -39,6 +39,7 @@ import org.alfresco.web.app.context.UIContextService; import org.alfresco.web.bean.actions.handlers.SimpleWorkflowHandler; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.bean.workflow.WorkflowUtil; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.Utils.URLMode; import org.alfresco.web.ui.common.component.UIActionLink; diff --git a/source/java/org/alfresco/web/bean/CheckinCheckoutBean.java b/source/java/org/alfresco/web/bean/CheckinCheckoutBean.java index 9a90fb796a..f58e734bf9 100644 --- a/source/java/org/alfresco/web/bean/CheckinCheckoutBean.java +++ b/source/java/org/alfresco/web/bean/CheckinCheckoutBean.java @@ -1,1050 +1,1051 @@ -/* - * 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. - */ -package org.alfresco.web.bean; - -import java.io.File; -import java.io.Serializable; -import java.text.MessageFormat; -import java.util.HashMap; -import java.util.Map; - -import javax.faces.context.FacesContext; -import javax.faces.event.ActionEvent; -import javax.transaction.UserTransaction; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.repo.version.VersionModel; -import org.alfresco.repo.workflow.WorkflowModel; -import org.alfresco.service.cmr.coci.CheckOutCheckInService; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.ContentData; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.cmr.repository.ContentService; -import org.alfresco.service.cmr.repository.ContentWriter; -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.cmr.version.Version; -import org.alfresco.service.cmr.version.VersionType; -import org.alfresco.service.cmr.workflow.WorkflowService; -import org.alfresco.service.cmr.workflow.WorkflowTask; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.web.app.AlfrescoNavigationHandler; -import org.alfresco.web.app.Application; -import org.alfresco.web.app.context.UIContextService; -import org.alfresco.web.app.servlet.DownloadContentServlet; -import org.alfresco.web.bean.repository.Node; -import org.alfresco.web.bean.repository.Repository; -import org.alfresco.web.ui.common.Utils; -import org.alfresco.web.ui.common.component.UIActionLink; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * @author Kevin Roast - */ -public class CheckinCheckoutBean -{ - // ------------------------------------------------------------------------------ - // Bean property getters and setters - - /** - * @param navigator The NavigationBean to set. - */ - public void setNavigator(NavigationBean navigator) - { - this.navigator = navigator; - } - - /** - * @return Returns the BrowseBean. - */ - public BrowseBean getBrowseBean() - { - return this.browseBean; - } - - /** - * @param browseBean The BrowseBean to set. - */ - public void setBrowseBean(BrowseBean browseBean) - { - this.browseBean = browseBean; - } - - /** - * @return Returns the NodeService. - */ - public NodeService getNodeService() - { - return this.nodeService; - } - - /** - * @param nodeService The NodeService to set. - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * @return Returns the VersionOperationsService. - */ - public CheckOutCheckInService getVersionOperationsService() - { - return this.versionOperationsService; - } - - /** - * @param versionOperationsService The VersionOperationsService to set. - */ - public void setVersionOperationsService(CheckOutCheckInService versionOperationsService) - { - this.versionOperationsService = versionOperationsService; - } - - /** - * @return Returns the ContentService. - */ - public ContentService getContentService() - { - return this.contentService; - } - - /** - * @param contentService The ContentService to set. - */ - public void setContentService(ContentService contentService) - { - this.contentService = contentService; - } - - /** - * @param workflowService The WorkflowService to set. - */ - public void setWorkflowService(WorkflowService workflowService) - { - this.workflowService = workflowService; - } - - /** - * @return The document node being used for the current operation - */ - public Node getDocument() - { - return this.document; - } - - /** - * @param document The document node to be used for the current operation - */ - public void setDocument(Node document) - { - this.document = document; - } - - /** - * @return Returns the working copy Document. - */ - public Node getWorkingDocument() - { - return this.workingDocument; - } - - /** - * @param workingDocument The working copy Document to set. - */ - public void setWorkingDocument(Node workingDocument) - { - this.workingDocument = workingDocument; - } - - /** - * Determines whether the document being checked in has - * the versionable aspect applied - * - * @return true if the versionable aspect is applied - */ - public boolean isVersionable() - { - return getDocument().hasAspect(ContentModel.ASPECT_VERSIONABLE); - } - - /** - * @param keepCheckedOut The keepCheckedOut to set. - */ - public void setKeepCheckedOut(boolean keepCheckedOut) - { - this.keepCheckedOut = keepCheckedOut; - } - - /** - * @return Returns the keepCheckedOut. - */ - public boolean getKeepCheckedOut() - { - return this.keepCheckedOut; - } - - /** - * @param minorChange The minorChange to set. - */ - public void setMinorChange(boolean minorChange) - { - this.minorChange = minorChange; - } - - /** - * @return Returns the minorChange flag. - */ - public boolean getMinorChange() - { - return this.minorChange; - } - - /** - * @return Returns the version history notes. - */ - public String getVersionNotes() - { - return this.versionNotes; - } - - /** - * @param versionNotes The version history notes to set. - */ - public void setVersionNotes(String versionNotes) - { - this.versionNotes = versionNotes; - } - - /** - * @return Returns the selected Space Id. - */ - public NodeRef getSelectedSpaceId() - { - return this.selectedSpaceId; - } - - /** - * @param selectedSpaceId The selected Space Id to set. - */ - public void setSelectedSpaceId(NodeRef selectedSpaceId) - { - this.selectedSpaceId = selectedSpaceId; - } - - /** - * @return Returns the copy location. Either the current or other space. - */ - public String getCopyLocation() - { - if (this.fileName != null) - { - return CheckinCheckoutBean.COPYLOCATION_OTHER; - } - else - { - return this.copyLocation; - } - } - - /** - * @param copyLocation The copy location. Either the current or other space. - */ - public void setCopyLocation(String copyLocation) - { - this.copyLocation = copyLocation; - } - - /** - * @return Returns the message to display when a file has been uploaded - */ - public String getFileUploadSuccessMsg() - { - String msg = Application.getMessage(FacesContext.getCurrentInstance(), "file_upload_success"); - return MessageFormat.format(msg, new Object[] {getFileName()}); - } - - /** - * @return Returns the name of the file - */ - public String getFileName() - { - // try and retrieve the file and filename from the file upload bean - // representing the file we previously uploaded. - FacesContext ctx = FacesContext.getCurrentInstance(); - FileUploadBean fileBean = (FileUploadBean)ctx.getExternalContext().getSessionMap(). - get(FileUploadBean.FILE_UPLOAD_BEAN_NAME); - if (fileBean != null) - { - this.file = fileBean.getFile(); - this.fileName = fileBean.getFileName(); - } - - return this.fileName; - } - - /** - * @param fileName The name of the file - */ - public void setFileName(String fileName) - { - this.fileName = fileName; - - // we also need to keep the file upload bean in sync - FacesContext ctx = FacesContext.getCurrentInstance(); - FileUploadBean fileBean = (FileUploadBean)ctx.getExternalContext().getSessionMap(). - get(FileUploadBean.FILE_UPLOAD_BEAN_NAME); - if (fileBean != null) - { - fileBean.setFileName(this.fileName); - } - } - - /** - * @return Returns the document content used for HTML in-line editing. - */ - public String getDocumentContent() - { - return this.documentContent; - } - - /** - * @param documentContent The document content for HTML in-line editing. - */ - public void setDocumentContent(String documentContent) - { - this.documentContent = documentContent; - } - - /** - * @return Returns output from the in-line editor page. - */ - public String getEditorOutput() - { - return this.editorOutput; - } - - /** - * @param editorOutput The output from the in-line editor page - */ - public void setEditorOutput(String editorOutput) - { - this.editorOutput = editorOutput; - } - - - // ------------------------------------------------------------------------------ - // Navigation action event handlers - - /** - * Action event called by all actions that need to setup a Content Document context on the - * CheckinCheckoutBean before an action page/wizard is called. The context will be a Node in - * setDocument() which can be retrieved on action pages via getDocument(). - * - * @param event ActionEvent - */ - public void setupContentAction(ActionEvent event) - { - UIActionLink link = (UIActionLink)event.getComponent(); - Map params = link.getParameterMap(); - String id = params.get("id"); - if (id != null && id.length() != 0) - { - setupContentDocument(id); - } - else - { - setDocument(null); - } - - resetState(); - } - - public void setupWorkflowContentAction(ActionEvent event) - { - // do the common processing - setupContentAction(event); - - // retrieve the id of the task - UIActionLink link = (UIActionLink)event.getComponent(); - Map params = link.getParameterMap(); - this.workflowTaskId = params.get("taskId"); - - this.isWorkflowAction = true; - - if (logger.isDebugEnabled()) - logger.debug("Setup for workflow package action for task id: " + this.workflowTaskId); - } - - /** - * Setup a content document node context - * - * @param id GUID of the node to setup as the content document context - * - * @return The Node - */ - private Node setupContentDocument(String id) - { - if (logger.isDebugEnabled()) - logger.debug("Setup for action, setting current document to: " + id); - - Node node = null; - - try - { - // create the node ref, then our node representation - NodeRef ref = new NodeRef(Repository.getStoreRef(), id); - node = new Node(ref); - - // create content URL to the content download servlet with ID and expected filename - // the myfile part will be ignored by the servlet but gives the browser a hint - String url = DownloadContentServlet.generateDownloadURL(ref, node.getName()); - node.getProperties().put("url", url); - node.getProperties().put("workingCopy", node.hasAspect(ContentModel.ASPECT_WORKING_COPY)); - node.getProperties().put("fileType32", Utils.getFileTypeImage(node.getName(), false)); - - // remember the document - setDocument(node); - - // refresh the UI, calling this method now is fine as it basically makes sure certain - // beans clear the state - so when we finish here other beans will have been reset - UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans(); - } - catch (InvalidNodeRefException refErr) - { - Utils.addErrorMessage(MessageFormat.format(Application.getMessage( - FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {id}) ); - } - - return node; - } - - /** - * Action called upon completion of the Check Out file page - */ - public String checkoutFile() - { - String outcome = null; - - UserTransaction tx = null; - - Node node = getDocument(); - if (node != null) - { - try - { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - if (logger.isDebugEnabled()) - logger.debug("Trying to checkout content node Id: " + node.getId()); - - // checkout the node content to create a working copy - if (logger.isDebugEnabled()) - { - logger.debug("Checkout copy location: " + getCopyLocation()); - logger.debug("Selected Space Id: " + this.selectedSpaceId); - } - NodeRef workingCopyRef = null; - if (getCopyLocation().equals(COPYLOCATION_OTHER) && this.selectedSpaceId != null) - { - // checkout to a arbituary parent Space - NodeRef destRef = this.selectedSpaceId; - - ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(destRef); - workingCopyRef = this.versionOperationsService.checkout(node.getNodeRef(), - destRef, ContentModel.ASSOC_CONTAINS, childAssocRef.getQName()); - } - else - { - // checkout the content to the current space - workingCopyRef = this.versionOperationsService.checkout(node.getNodeRef()); - - // if this is a workflow action and there is a task id present we need - // to also link the working copy to the workflow package so it appears - // in the resources panel in the manage task dialog - if (this.isWorkflowAction && this.workflowTaskId != null) - { - WorkflowTask task = this.workflowService.getTaskById(this.workflowTaskId); - if (task != null) - { - NodeRef workflowPackage = (NodeRef)task.properties.get(WorkflowModel.ASSOC_PACKAGE); - if (workflowPackage != null) - { - this.nodeService.addChild(workflowPackage, workingCopyRef, - ContentModel.ASSOC_CONTAINS, QName.createQName( - NamespaceService.CONTENT_MODEL_1_0_URI, - QName.createValidLocalName((String)this.nodeService.getProperty( - workingCopyRef, ContentModel.PROP_NAME)))); - - if (logger.isDebugEnabled()) - logger.debug("Added working copy to workflow package: " + workflowPackage); - } - } - } - } - - // set the working copy Node instance - Node workingCopy = new Node(workingCopyRef); - setWorkingDocument(workingCopy); - - // create content URL to the content download servlet with ID and expected filename - // the myfile part will be ignored by the servlet but gives the browser a hint - String url = DownloadContentServlet.generateDownloadURL(workingCopyRef, workingCopy.getName()); - - workingCopy.getProperties().put("url", url); - workingCopy.getProperties().put("fileType32", Utils.getFileTypeImage(workingCopy.getName(), false)); - - // commit the transaction - tx.commit(); - - // show the page that display the checkout link - outcome = "checkoutFileLink"; - } - catch (Throwable err) - { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} - Utils.addErrorMessage(Application.getMessage( - FacesContext.getCurrentInstance(), MSG_ERROR_CHECKOUT) + err.getMessage(), err); - } - } - else - { - logger.warn("WARNING: checkoutFile called without a current Document!"); - } - - return outcome; - } - - /** - * Action called upon completion of the Check Out file Link download page - */ - public String checkoutFileOK() - { - String outcome = null; - - Node node = getWorkingDocument(); - if (node != null) - { - // reset the underlying node - if (this.browseBean.getDocument() != null) - { - this.browseBean.getDocument().reset(); - } - - // clean up and clear action context - resetState(); - setDocument(null); - setWorkingDocument(null); - - outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; - } - else - { - logger.warn("WARNING: checkoutFileOK called without a current WorkingDocument!"); - } - - return outcome; - } - - /** - * Action called upon completion of the Edit File download page - */ - public String editFileOK() - { - String outcome = null; - - Node node = getDocument(); - if (node != null) - { - // clean up and clear action context - resetState(); - setDocument(null); - setWorkingDocument(null); - - outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; - } - else - { - logger.warn("WARNING: editFileOK called without a current Document!"); - } - - return outcome; - } - - /** - * Action handler called to calculate which editing screen to display based on the mimetype - * of a document. If appropriate, the in-line editing screen will be shown. - */ - public void editFile(ActionEvent event) - { - UIActionLink link = (UIActionLink)event.getComponent(); - Map params = link.getParameterMap(); - String id = params.get("id"); - if (id != null && id.length() != 0) - { - boolean editingInline = false; - Node node = setupContentDocument(id); - - // detect the inline editing aspect to see which edit mode to use - if (node.hasAspect(ContentModel.ASPECT_INLINEEDITABLE) && - node.getProperties().get(ContentModel.PROP_EDITINLINE) != null && - ((Boolean)node.getProperties().get(ContentModel.PROP_EDITINLINE)).booleanValue() == true) - { - // retrieve the content reader for this node - ContentReader reader = getContentService().getReader(node.getNodeRef(), ContentModel.PROP_CONTENT); - if (reader != null) - { - editingInline = true; - String mimetype = reader.getMimetype(); - - // calculate which editor screen to display - if (MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(mimetype) || - MimetypeMap.MIMETYPE_XML.equals(mimetype) || - MimetypeMap.MIMETYPE_TEXT_CSS.equals(mimetype) || - MimetypeMap.MIMETYPE_JAVASCRIPT.equals(mimetype)) - { - // make content available to the editing screen - setEditorOutput(reader.getContentString()); - - // navigate to appropriate screen - FacesContext fc = FacesContext.getCurrentInstance(); - this.navigator.setupDispatchContext(node); - String outcome; - if (MimetypeMap.MIMETYPE_XML.equals(mimetype)) - { - outcome = "dialog:editXmlInline"; - } - else - { - outcome = "dialog:editTextInline"; - } - fc.getApplication().getNavigationHandler().handleNavigation(fc, null, outcome); - } - else - { - // make content available to the editing screen - setDocumentContent(reader.getContentString()); - setEditorOutput(null); - - // navigate to appropriate screen - FacesContext fc = FacesContext.getCurrentInstance(); - this.navigator.setupDispatchContext(node); - fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editHtmlInline"); - } - } - } - - if (editingInline == false) - { - // normal downloadable document - FacesContext fc = FacesContext.getCurrentInstance(); - this.navigator.setupDispatchContext(node); - fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editFile"); - } - } - } - - /** - * Action handler called to set the content of a node from an inline editing page. - */ - public String editInlineOK() - { - String outcome = null; - - UserTransaction tx = null; - - Node node = getDocument(); - if (node != null) - { - try - { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - if (logger.isDebugEnabled()) - logger.debug("Trying to update content node Id: " + node.getId()); - - // get an updating writer that we can use to modify the content on the current node - ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); - writer.putContent(this.editorOutput); - - // commit the transaction - tx.commit(); - - // clean up and clear action context - resetState(); - setDocument(null); - setDocumentContent(null); - setEditorOutput(null); - - outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; - } - catch (Throwable err) - { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} - Utils.addErrorMessage(Application.getMessage( - FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE) + err.getMessage()); - } - } - else - { - logger.warn("WARNING: editInlineOK called without a current Document!"); - } - - return outcome; - } - - /** - * Action to undo the checkout of a document just checked out from the checkout screen. - */ - public String undoCheckout() - { - String outcome = null; - - Node node = getWorkingDocument(); - if (node != null) - { - try - { - // try to cancel checkout of the working copy - this.versionOperationsService.cancelCheckout(node.getNodeRef()); - - resetState(); - - outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; - } - catch (Throwable err) - { - Utils.addErrorMessage(Application.getMessage( - FacesContext.getCurrentInstance(), MSG_ERROR_CANCELCHECKOUT) + err.getMessage(), err); - } - } - else - { - logger.warn("WARNING: undoCheckout called without a current WorkingDocument!"); - } - - return outcome; - } - - /** - * Action to undo the checkout of a locked document. This document may either by the original copy - * or the working copy node. Therefore calculate which it is, if the working copy is found then - * we simply cancel checkout on that document. If the original copy is found then we need to find - * the appropriate working copy and perform the action on that node. - */ - public String undoCheckoutFile() - { - String outcome = null; - - Node node = getDocument(); - if (node != null) - { - try - { - if (node.hasAspect(ContentModel.ASPECT_WORKING_COPY)) - { - this.versionOperationsService.cancelCheckout(node.getNodeRef()); - } - else if (node.hasAspect(ContentModel.ASPECT_LOCKABLE)) - { - // TODO: find the working copy for this document and cancel the checkout on it - // is this possible? as currently only the workingcopy aspect has the copyReference - // attribute - this means we cannot find out where the copy is to cancel it! - // can we construct an XPath node lookup? - throw new RuntimeException("NOT IMPLEMENTED"); - } - else - { - throw new IllegalStateException("Node supplied for undo checkout has neither Working Copy or Locked aspect!"); - } - - outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; - - if (this.isWorkflowAction == false) - { - outcome = outcome + AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse"; - } - - resetState(); - } - catch (Throwable err) - { - Utils.addErrorMessage(MSG_ERROR_CANCELCHECKOUT + err.getMessage(), err); - } - } - else - { - logger.warn("WARNING: undoCheckout called without a current WorkingDocument!"); - } - - return outcome; - } - - /** - * Action called upon completion of the Check In file page - */ - public String checkinFileOK() - { - String outcome = null; - - UserTransaction tx = null; - - // NOTE: for checkin the document node _is_ the working document! - Node node = getDocument(); - if (node != null && (getCopyLocation().equals(COPYLOCATION_CURRENT) || this.getFileName() != null)) - { - try - { - FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - if (logger.isDebugEnabled()) - logger.debug("Trying to checkin content node Id: " + node.getId()); - - // we can either checkin the content from the current working copy node - // which would have been previously updated by the user - String contentUrl; - if (getCopyLocation().equals(COPYLOCATION_CURRENT)) - { - ContentData contentData = (ContentData) node.getProperties().get(ContentModel.PROP_CONTENT); - contentUrl = (contentData == null ? null : contentData.getContentUrl()); - } - // or specify a specific file as the content instead - else - { - // add the content to an anonymous but permanent writer location - // we can then retrieve the URL to the content to to be set on the node during checkin - ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); - // also update the mime type in case a different type of file is uploaded - String mimeType = Repository.getMimeTypeForFileName(context, this.fileName); - writer.setMimetype(mimeType); - writer.putContent(this.file); - contentUrl = writer.getContentUrl(); - } - - if (contentUrl == null || contentUrl.length() == 0) - { - throw new IllegalStateException("Content URL is empty for specified working copy content node!"); - } - - // add version history text to props - Map props = new HashMap(1, 1.0f); - props.put(Version.PROP_DESCRIPTION, this.versionNotes); - // set the flag for minor or major change - if (this.minorChange) - { - props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR); - } - else - { - props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR); - } - - // perform the checkin - this.versionOperationsService.checkin(node.getNodeRef(), - props, contentUrl, this.keepCheckedOut); - - // commit the transaction - tx.commit(); - - outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; - - if (this.isWorkflowAction == false) - { - outcome = outcome + AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse"; - } - - // clear action context - setDocument(null); - resetState(); - } - catch (Throwable err) - { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} - Utils.addErrorMessage(Application.getMessage( - FacesContext.getCurrentInstance(), MSG_ERROR_CHECKIN) + err.getMessage(), err); - } - } - else - { - logger.warn("WARNING: checkinFileOK called without a current Document!"); - } - - return outcome; - } - - /** - * Action called upon completion of the Update File page - */ - public String updateFileOK() - { - String outcome = null; - - UserTransaction tx = null; - - // NOTE: for update the document node _is_ the working document! - Node node = getDocument(); - if (node != null && this.getFileName() != null) - { - try - { - FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - if (logger.isDebugEnabled()) - logger.debug("Trying to update content node Id: " + node.getId()); - - // get an updating writer that we can use to modify the content on the current node - ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); - - // also update the mime type in case a different type of file is uploaded - String mimeType = Repository.getMimeTypeForFileName(context, this.fileName); - writer.setMimetype(mimeType); - - writer.putContent(this.file); - - // commit the transaction - tx.commit(); - - // clear action context - setDocument(null); - resetState(); - - outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; - } - catch (Throwable err) - { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} - Utils.addErrorMessage(Application.getMessage( - FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE) + err.getMessage(), err); - } - } - else - { - logger.warn("WARNING: updateFileOK called without a current Document!"); - } - - return outcome; - } - - /** - * Deals with the cancel button being pressed on the check in file page - */ - public String cancel() - { - // reset the state - resetState(); - - return AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; - } - - /** - * Clear form state and upload file bean - */ - private void resetState() - { - // delete the temporary file we uploaded earlier - if (this.file != null) - { - this.file.delete(); - } - - this.file = null; - this.fileName = null; - this.keepCheckedOut = false; - this.minorChange = true; - this.copyLocation = COPYLOCATION_CURRENT; - this.versionNotes = ""; - this.selectedSpaceId = null; - this.isWorkflowAction = false; - this.workflowTaskId = null; - - // remove the file upload bean from the session - FacesContext ctx = FacesContext.getCurrentInstance(); - ctx.getExternalContext().getSessionMap().remove(FileUploadBean.FILE_UPLOAD_BEAN_NAME); - } - - - // ------------------------------------------------------------------------------ - // Private data - - private static Log logger = LogFactory.getLog(CheckinCheckoutBean.class); - - /** I18N messages */ - public static final String MSG_ERROR_CHECKIN = "error_checkin"; - public static final String MSG_ERROR_CANCELCHECKOUT = "error_cancel_checkout"; - public static final String MSG_ERROR_UPDATE = "error_update"; - public static final String MSG_ERROR_CHECKOUT = "error_checkout"; - - /** constants for copy location selection */ - private static final String COPYLOCATION_CURRENT = "current"; - private static final String COPYLOCATION_OTHER = "other"; - - /** The current document */ - private Node document; - - /** The working copy of the document we are checking out */ - private Node workingDocument; - - /** Content of the document used for HTML in-line editing */ - private String documentContent; - - /** Content of the document returned from in-line editing */ - private String editorOutput; - - /** transient form and upload properties */ - private File file; - private String fileName; - private boolean keepCheckedOut = false; - private boolean minorChange = true; - private boolean isWorkflowAction = false; - private String workflowTaskId; - private String copyLocation = COPYLOCATION_CURRENT; - private String versionNotes = ""; - private NodeRef selectedSpaceId = null; - - /** The BrowseBean to be used by the bean */ - protected BrowseBean browseBean; - - /** The NavigationBean bean reference */ - protected NavigationBean navigator; - - /** The NodeService to be used by the bean */ - protected NodeService nodeService; - - /** The VersionOperationsService to be used by the bean */ - protected CheckOutCheckInService versionOperationsService; - - /** The ContentService to be used by the bean */ - protected ContentService contentService; - - /** The WorkflowService to be used by the bean */ - protected WorkflowService workflowService; -} +/* + * 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. + */ +package org.alfresco.web.bean; + +import java.io.File; +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +import javax.faces.context.FacesContext; +import javax.faces.event.ActionEvent; +import javax.transaction.UserTransaction; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.version.VersionModel; +import org.alfresco.repo.workflow.WorkflowModel; +import org.alfresco.service.cmr.coci.CheckOutCheckInService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentWriter; +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.cmr.version.Version; +import org.alfresco.service.cmr.version.VersionType; +import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.web.app.AlfrescoNavigationHandler; +import org.alfresco.web.app.Application; +import org.alfresco.web.app.context.UIContextService; +import org.alfresco.web.app.servlet.DownloadContentServlet; +import org.alfresco.web.bean.repository.Node; +import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.ui.common.Utils; +import org.alfresco.web.ui.common.component.UIActionLink; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author Kevin Roast + */ +public class CheckinCheckoutBean +{ + // ------------------------------------------------------------------------------ + // Bean property getters and setters + + /** + * @param navigator The NavigationBean to set. + */ + public void setNavigator(NavigationBean navigator) + { + this.navigator = navigator; + } + + /** + * @return Returns the BrowseBean. + */ + public BrowseBean getBrowseBean() + { + return this.browseBean; + } + + /** + * @param browseBean The BrowseBean to set. + */ + public void setBrowseBean(BrowseBean browseBean) + { + this.browseBean = browseBean; + } + + /** + * @return Returns the NodeService. + */ + public NodeService getNodeService() + { + return this.nodeService; + } + + /** + * @param nodeService The NodeService to set. + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * @return Returns the VersionOperationsService. + */ + public CheckOutCheckInService getVersionOperationsService() + { + return this.versionOperationsService; + } + + /** + * @param versionOperationsService The VersionOperationsService to set. + */ + public void setVersionOperationsService(CheckOutCheckInService versionOperationsService) + { + this.versionOperationsService = versionOperationsService; + } + + /** + * @return Returns the ContentService. + */ + public ContentService getContentService() + { + return this.contentService; + } + + /** + * @param contentService The ContentService to set. + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } + + /** + * @param workflowService The WorkflowService to set. + */ + public void setWorkflowService(WorkflowService workflowService) + { + this.workflowService = workflowService; + } + + /** + * @return The document node being used for the current operation + */ + public Node getDocument() + { + return this.document; + } + + /** + * @param document The document node to be used for the current operation + */ + public void setDocument(Node document) + { + this.document = document; + } + + /** + * @return Returns the working copy Document. + */ + public Node getWorkingDocument() + { + return this.workingDocument; + } + + /** + * @param workingDocument The working copy Document to set. + */ + public void setWorkingDocument(Node workingDocument) + { + this.workingDocument = workingDocument; + } + + /** + * Determines whether the document being checked in has + * the versionable aspect applied + * + * @return true if the versionable aspect is applied + */ + public boolean isVersionable() + { + return getDocument().hasAspect(ContentModel.ASPECT_VERSIONABLE); + } + + /** + * @param keepCheckedOut The keepCheckedOut to set. + */ + public void setKeepCheckedOut(boolean keepCheckedOut) + { + this.keepCheckedOut = keepCheckedOut; + } + + /** + * @return Returns the keepCheckedOut. + */ + public boolean getKeepCheckedOut() + { + return this.keepCheckedOut; + } + + /** + * @param minorChange The minorChange to set. + */ + public void setMinorChange(boolean minorChange) + { + this.minorChange = minorChange; + } + + /** + * @return Returns the minorChange flag. + */ + public boolean getMinorChange() + { + return this.minorChange; + } + + /** + * @return Returns the version history notes. + */ + public String getVersionNotes() + { + return this.versionNotes; + } + + /** + * @param versionNotes The version history notes to set. + */ + public void setVersionNotes(String versionNotes) + { + this.versionNotes = versionNotes; + } + + /** + * @return Returns the selected Space Id. + */ + public NodeRef getSelectedSpaceId() + { + return this.selectedSpaceId; + } + + /** + * @param selectedSpaceId The selected Space Id to set. + */ + public void setSelectedSpaceId(NodeRef selectedSpaceId) + { + this.selectedSpaceId = selectedSpaceId; + } + + /** + * @return Returns the copy location. Either the current or other space. + */ + public String getCopyLocation() + { + if (this.fileName != null) + { + return CheckinCheckoutBean.COPYLOCATION_OTHER; + } + else + { + return this.copyLocation; + } + } + + /** + * @param copyLocation The copy location. Either the current or other space. + */ + public void setCopyLocation(String copyLocation) + { + this.copyLocation = copyLocation; + } + + /** + * @return Returns the message to display when a file has been uploaded + */ + public String getFileUploadSuccessMsg() + { + String msg = Application.getMessage(FacesContext.getCurrentInstance(), "file_upload_success"); + return MessageFormat.format(msg, new Object[] {getFileName()}); + } + + /** + * @return Returns the name of the file + */ + public String getFileName() + { + // try and retrieve the file and filename from the file upload bean + // representing the file we previously uploaded. + FacesContext ctx = FacesContext.getCurrentInstance(); + FileUploadBean fileBean = (FileUploadBean)ctx.getExternalContext().getSessionMap(). + get(FileUploadBean.FILE_UPLOAD_BEAN_NAME); + if (fileBean != null) + { + this.file = fileBean.getFile(); + this.fileName = fileBean.getFileName(); + } + + return this.fileName; + } + + /** + * @param fileName The name of the file + */ + public void setFileName(String fileName) + { + this.fileName = fileName; + + // we also need to keep the file upload bean in sync + FacesContext ctx = FacesContext.getCurrentInstance(); + FileUploadBean fileBean = (FileUploadBean)ctx.getExternalContext().getSessionMap(). + get(FileUploadBean.FILE_UPLOAD_BEAN_NAME); + if (fileBean != null) + { + fileBean.setFileName(this.fileName); + } + } + + /** + * @return Returns the document content used for HTML in-line editing. + */ + public String getDocumentContent() + { + return this.documentContent; + } + + /** + * @param documentContent The document content for HTML in-line editing. + */ + public void setDocumentContent(String documentContent) + { + this.documentContent = documentContent; + } + + /** + * @return Returns output from the in-line editor page. + */ + public String getEditorOutput() + { + return this.editorOutput; + } + + /** + * @param editorOutput The output from the in-line editor page + */ + public void setEditorOutput(String editorOutput) + { + this.editorOutput = editorOutput; + } + + + // ------------------------------------------------------------------------------ + // Navigation action event handlers + + /** + * Action event called by all actions that need to setup a Content Document context on the + * CheckinCheckoutBean before an action page/wizard is called. The context will be a Node in + * setDocument() which can be retrieved on action pages via getDocument(). + * + * @param event ActionEvent + */ + public void setupContentAction(ActionEvent event) + { + UIActionLink link = (UIActionLink)event.getComponent(); + Map params = link.getParameterMap(); + String id = params.get("id"); + if (id != null && id.length() != 0) + { + setupContentDocument(id); + } + else + { + setDocument(null); + } + + resetState(); + } + + public void setupWorkflowContentAction(ActionEvent event) + { + // do the common processing + setupContentAction(event); + + // retrieve the id of the task + UIActionLink link = (UIActionLink)event.getComponent(); + Map params = link.getParameterMap(); + this.workflowTaskId = params.get("taskId"); + + this.isWorkflowAction = true; + + if (logger.isDebugEnabled()) + logger.debug("Setup for workflow package action for task id: " + this.workflowTaskId); + } + + /** + * Setup a content document node context + * + * @param id GUID of the node to setup as the content document context + * + * @return The Node + */ + private Node setupContentDocument(String id) + { + if (logger.isDebugEnabled()) + logger.debug("Setup for action, setting current document to: " + id); + + Node node = null; + + try + { + // create the node ref, then our node representation + NodeRef ref = new NodeRef(Repository.getStoreRef(), id); + node = new Node(ref); + + // create content URL to the content download servlet with ID and expected filename + // the myfile part will be ignored by the servlet but gives the browser a hint + String url = DownloadContentServlet.generateDownloadURL(ref, node.getName()); + node.getProperties().put("url", url); + node.getProperties().put("workingCopy", node.hasAspect(ContentModel.ASPECT_WORKING_COPY)); + node.getProperties().put("fileType32", Utils.getFileTypeImage(node.getName(), false)); + + // remember the document + setDocument(node); + + // refresh the UI, calling this method now is fine as it basically makes sure certain + // beans clear the state - so when we finish here other beans will have been reset + UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans(); + } + catch (InvalidNodeRefException refErr) + { + Utils.addErrorMessage(MessageFormat.format(Application.getMessage( + FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {id}) ); + } + + return node; + } + + /** + * Action called upon completion of the Check Out file page + */ + public String checkoutFile() + { + String outcome = null; + + UserTransaction tx = null; + + Node node = getDocument(); + if (node != null) + { + try + { + tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); + tx.begin(); + + if (logger.isDebugEnabled()) + logger.debug("Trying to checkout content node Id: " + node.getId()); + + // checkout the node content to create a working copy + if (logger.isDebugEnabled()) + { + logger.debug("Checkout copy location: " + getCopyLocation()); + logger.debug("Selected Space Id: " + this.selectedSpaceId); + } + NodeRef workingCopyRef = null; + if (getCopyLocation().equals(COPYLOCATION_OTHER) && this.selectedSpaceId != null) + { + // checkout to a arbituary parent Space + NodeRef destRef = this.selectedSpaceId; + + ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(destRef); + workingCopyRef = this.versionOperationsService.checkout(node.getNodeRef(), + destRef, ContentModel.ASSOC_CONTAINS, childAssocRef.getQName()); + } + else + { + // checkout the content to the current space + workingCopyRef = this.versionOperationsService.checkout(node.getNodeRef()); + + // if this is a workflow action and there is a task id present we need + // to also link the working copy to the workflow package so it appears + // in the resources panel in the manage task dialog + if (this.isWorkflowAction && this.workflowTaskId != null) + { + WorkflowTask task = this.workflowService.getTaskById(this.workflowTaskId); + if (task != null) + { + NodeRef workflowPackage = (NodeRef)task.properties.get(WorkflowModel.ASSOC_PACKAGE); + if (workflowPackage != null) + { + this.nodeService.addChild(workflowPackage, workingCopyRef, + ContentModel.ASSOC_CONTAINS, QName.createQName( + NamespaceService.CONTENT_MODEL_1_0_URI, + QName.createValidLocalName((String)this.nodeService.getProperty( + workingCopyRef, ContentModel.PROP_NAME)))); + + if (logger.isDebugEnabled()) + logger.debug("Added working copy to workflow package: " + workflowPackage); + } + } + } + } + + // set the working copy Node instance + Node workingCopy = new Node(workingCopyRef); + setWorkingDocument(workingCopy); + + // create content URL to the content download servlet with ID and expected filename + // the myfile part will be ignored by the servlet but gives the browser a hint + String url = DownloadContentServlet.generateDownloadURL(workingCopyRef, workingCopy.getName()); + + workingCopy.getProperties().put("url", url); + workingCopy.getProperties().put("fileType32", Utils.getFileTypeImage(workingCopy.getName(), false)); + + // commit the transaction + tx.commit(); + + // show the page that display the checkout link + outcome = "checkoutFileLink"; + } + catch (Throwable err) + { + // rollback the transaction + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + Utils.addErrorMessage(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_CHECKOUT) + err.getMessage(), err); + } + } + else + { + logger.warn("WARNING: checkoutFile called without a current Document!"); + } + + return outcome; + } + + /** + * Action called upon completion of the Check Out file Link download page + */ + public String checkoutFileOK() + { + String outcome = null; + + Node node = getWorkingDocument(); + if (node != null) + { + // reset the underlying node + if (this.browseBean.getDocument() != null) + { + this.browseBean.getDocument().reset(); + } + + // clean up and clear action context + resetState(); + setDocument(null); + setWorkingDocument(null); + + outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; + } + else + { + logger.warn("WARNING: checkoutFileOK called without a current WorkingDocument!"); + } + + return outcome; + } + + /** + * Action called upon completion of the Edit File download page + */ + public String editFileOK() + { + String outcome = null; + + Node node = getDocument(); + if (node != null) + { + // clean up and clear action context + resetState(); + setDocument(null); + setWorkingDocument(null); + + outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; + } + else + { + logger.warn("WARNING: editFileOK called without a current Document!"); + } + + return outcome; + } + + /** + * Action handler called to calculate which editing screen to display based on the mimetype + * of a document. If appropriate, the in-line editing screen will be shown. + */ + public void editFile(ActionEvent event) + { + UIActionLink link = (UIActionLink)event.getComponent(); + Map params = link.getParameterMap(); + String id = params.get("id"); + if (id != null && id.length() != 0) + { + boolean editingInline = false; + Node node = setupContentDocument(id); + + // detect the inline editing aspect to see which edit mode to use + if (node.hasAspect(ContentModel.ASPECT_INLINEEDITABLE) && + node.getProperties().get(ContentModel.PROP_EDITINLINE) != null && + ((Boolean)node.getProperties().get(ContentModel.PROP_EDITINLINE)).booleanValue() == true) + { + // retrieve the content reader for this node + ContentReader reader = getContentService().getReader(node.getNodeRef(), ContentModel.PROP_CONTENT); + if (reader != null) + { + editingInline = true; + String mimetype = reader.getMimetype(); + + // calculate which editor screen to display + if (MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(mimetype) || + MimetypeMap.MIMETYPE_XML.equals(mimetype) || + MimetypeMap.MIMETYPE_TEXT_CSS.equals(mimetype) || + MimetypeMap.MIMETYPE_JAVASCRIPT.equals(mimetype)) + { + // make content available to the editing screen + setEditorOutput(reader.getContentString()); + + // navigate to appropriate screen + FacesContext fc = FacesContext.getCurrentInstance(); + this.navigator.setupDispatchContext(node); + String outcome; + if (MimetypeMap.MIMETYPE_XML.equals(mimetype)) + { + outcome = "dialog:editXmlInline"; + } + else + { + outcome = "dialog:editTextInline"; + } + fc.getApplication().getNavigationHandler().handleNavigation(fc, null, outcome); + } + else + { + // make content available to the editing screen + setDocumentContent(reader.getContentString()); + setEditorOutput(null); + + // navigate to appropriate screen + FacesContext fc = FacesContext.getCurrentInstance(); + this.navigator.setupDispatchContext(node); + fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editHtmlInline"); + } + } + } + + if (editingInline == false) + { + // normal downloadable document + FacesContext fc = FacesContext.getCurrentInstance(); + this.navigator.setupDispatchContext(node); + fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editFile"); + } + } + } + + /** + * Action handler called to set the content of a node from an inline editing page. + */ + public String editInlineOK() + { + String outcome = null; + + UserTransaction tx = null; + + Node node = getDocument(); + if (node != null) + { + try + { + tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); + tx.begin(); + + if (logger.isDebugEnabled()) + logger.debug("Trying to update content node Id: " + node.getId()); + + // get an updating writer that we can use to modify the content on the current node + ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); + writer.putContent(this.editorOutput); + + // commit the transaction + tx.commit(); + + // clean up and clear action context + resetState(); + setDocument(null); + setDocumentContent(null); + setEditorOutput(null); + + outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; + } + catch (Throwable err) + { + // rollback the transaction + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + Utils.addErrorMessage(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE) + err.getMessage()); + } + } + else + { + logger.warn("WARNING: editInlineOK called without a current Document!"); + } + + return outcome; + } + + /** + * Action to undo the checkout of a document just checked out from the checkout screen. + */ + public String undoCheckout() + { + String outcome = null; + + Node node = getWorkingDocument(); + if (node != null) + { + try + { + // try to cancel checkout of the working copy + this.versionOperationsService.cancelCheckout(node.getNodeRef()); + + resetState(); + + outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; + } + catch (Throwable err) + { + Utils.addErrorMessage(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_CANCELCHECKOUT) + err.getMessage(), err); + } + } + else + { + logger.warn("WARNING: undoCheckout called without a current WorkingDocument!"); + } + + return outcome; + } + + /** + * Action to undo the checkout of a locked document. This document may either by the original copy + * or the working copy node. Therefore calculate which it is, if the working copy is found then + * we simply cancel checkout on that document. If the original copy is found then we need to find + * the appropriate working copy and perform the action on that node. + */ + public String undoCheckoutFile() + { + String outcome = null; + + Node node = getDocument(); + if (node != null) + { + try + { + if (node.hasAspect(ContentModel.ASPECT_WORKING_COPY)) + { + this.versionOperationsService.cancelCheckout(node.getNodeRef()); + } + else if (node.hasAspect(ContentModel.ASPECT_LOCKABLE)) + { + // TODO: find the working copy for this document and cancel the checkout on it + // is this possible? as currently only the workingcopy aspect has the copyReference + // attribute - this means we cannot find out where the copy is to cancel it! + // can we construct an XPath node lookup? + throw new RuntimeException("NOT IMPLEMENTED"); + } + else + { + throw new IllegalStateException("Node supplied for undo checkout has neither Working Copy or Locked aspect!"); + } + + outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; + + if (this.isWorkflowAction == false) + { + outcome = outcome + AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse"; + } + + resetState(); + } + catch (Throwable err) + { + Utils.addErrorMessage(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_CANCELCHECKOUT) + err.getMessage(), err); + } + } + else + { + logger.warn("WARNING: undoCheckout called without a current WorkingDocument!"); + } + + return outcome; + } + + /** + * Action called upon completion of the Check In file page + */ + public String checkinFileOK() + { + String outcome = null; + + UserTransaction tx = null; + + // NOTE: for checkin the document node _is_ the working document! + Node node = getDocument(); + if (node != null && (getCopyLocation().equals(COPYLOCATION_CURRENT) || this.getFileName() != null)) + { + try + { + FacesContext context = FacesContext.getCurrentInstance(); + tx = Repository.getUserTransaction(context); + tx.begin(); + + if (logger.isDebugEnabled()) + logger.debug("Trying to checkin content node Id: " + node.getId()); + + // we can either checkin the content from the current working copy node + // which would have been previously updated by the user + String contentUrl; + if (getCopyLocation().equals(COPYLOCATION_CURRENT)) + { + ContentData contentData = (ContentData) node.getProperties().get(ContentModel.PROP_CONTENT); + contentUrl = (contentData == null ? null : contentData.getContentUrl()); + } + // or specify a specific file as the content instead + else + { + // add the content to an anonymous but permanent writer location + // we can then retrieve the URL to the content to to be set on the node during checkin + ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); + // also update the mime type in case a different type of file is uploaded + String mimeType = Repository.getMimeTypeForFileName(context, this.fileName); + writer.setMimetype(mimeType); + writer.putContent(this.file); + contentUrl = writer.getContentUrl(); + } + + if (contentUrl == null || contentUrl.length() == 0) + { + throw new IllegalStateException("Content URL is empty for specified working copy content node!"); + } + + // add version history text to props + Map props = new HashMap(1, 1.0f); + props.put(Version.PROP_DESCRIPTION, this.versionNotes); + // set the flag for minor or major change + if (this.minorChange) + { + props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR); + } + else + { + props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR); + } + + // perform the checkin + this.versionOperationsService.checkin(node.getNodeRef(), + props, contentUrl, this.keepCheckedOut); + + // commit the transaction + tx.commit(); + + outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; + + if (this.isWorkflowAction == false) + { + outcome = outcome + AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse"; + } + + // clear action context + setDocument(null); + resetState(); + } + catch (Throwable err) + { + // rollback the transaction + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + Utils.addErrorMessage(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_CHECKIN) + err.getMessage(), err); + } + } + else + { + logger.warn("WARNING: checkinFileOK called without a current Document!"); + } + + return outcome; + } + + /** + * Action called upon completion of the Update File page + */ + public String updateFileOK() + { + String outcome = null; + + UserTransaction tx = null; + + // NOTE: for update the document node _is_ the working document! + Node node = getDocument(); + if (node != null && this.getFileName() != null) + { + try + { + FacesContext context = FacesContext.getCurrentInstance(); + tx = Repository.getUserTransaction(context); + tx.begin(); + + if (logger.isDebugEnabled()) + logger.debug("Trying to update content node Id: " + node.getId()); + + // get an updating writer that we can use to modify the content on the current node + ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); + + // also update the mime type in case a different type of file is uploaded + String mimeType = Repository.getMimeTypeForFileName(context, this.fileName); + writer.setMimetype(mimeType); + + writer.putContent(this.file); + + // commit the transaction + tx.commit(); + + // clear action context + setDocument(null); + resetState(); + + outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; + } + catch (Throwable err) + { + // rollback the transaction + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + Utils.addErrorMessage(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE) + err.getMessage(), err); + } + } + else + { + logger.warn("WARNING: updateFileOK called without a current Document!"); + } + + return outcome; + } + + /** + * Deals with the cancel button being pressed on the check in file page + */ + public String cancel() + { + // reset the state + resetState(); + + return AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; + } + + /** + * Clear form state and upload file bean + */ + private void resetState() + { + // delete the temporary file we uploaded earlier + if (this.file != null) + { + this.file.delete(); + } + + this.file = null; + this.fileName = null; + this.keepCheckedOut = false; + this.minorChange = true; + this.copyLocation = COPYLOCATION_CURRENT; + this.versionNotes = ""; + this.selectedSpaceId = null; + this.isWorkflowAction = false; + this.workflowTaskId = null; + + // remove the file upload bean from the session + FacesContext ctx = FacesContext.getCurrentInstance(); + ctx.getExternalContext().getSessionMap().remove(FileUploadBean.FILE_UPLOAD_BEAN_NAME); + } + + + // ------------------------------------------------------------------------------ + // Private data + + private static Log logger = LogFactory.getLog(CheckinCheckoutBean.class); + + /** I18N messages */ + public static final String MSG_ERROR_CHECKIN = "error_checkin"; + public static final String MSG_ERROR_CANCELCHECKOUT = "error_cancel_checkout"; + public static final String MSG_ERROR_UPDATE = "error_update"; + public static final String MSG_ERROR_CHECKOUT = "error_checkout"; + + /** constants for copy location selection */ + private static final String COPYLOCATION_CURRENT = "current"; + private static final String COPYLOCATION_OTHER = "other"; + + /** The current document */ + private Node document; + + /** The working copy of the document we are checking out */ + private Node workingDocument; + + /** Content of the document used for HTML in-line editing */ + private String documentContent; + + /** Content of the document returned from in-line editing */ + private String editorOutput; + + /** transient form and upload properties */ + private File file; + private String fileName; + private boolean keepCheckedOut = false; + private boolean minorChange = true; + private boolean isWorkflowAction = false; + private String workflowTaskId; + private String copyLocation = COPYLOCATION_CURRENT; + private String versionNotes = ""; + private NodeRef selectedSpaceId = null; + + /** The BrowseBean to be used by the bean */ + protected BrowseBean browseBean; + + /** The NavigationBean bean reference */ + protected NavigationBean navigator; + + /** The NodeService to be used by the bean */ + protected NodeService nodeService; + + /** The VersionOperationsService to be used by the bean */ + protected CheckOutCheckInService versionOperationsService; + + /** The ContentService to be used by the bean */ + protected ContentService contentService; + + /** The WorkflowService to be used by the bean */ + protected WorkflowService workflowService; +} diff --git a/source/java/org/alfresco/web/bean/SearchContext.java b/source/java/org/alfresco/web/bean/SearchContext.java index cf5b0855e1..52f8dc4610 100644 --- a/source/java/org/alfresco/web/bean/SearchContext.java +++ b/source/java/org/alfresco/web/bean/SearchContext.java @@ -86,6 +86,7 @@ public final class SearchContext implements Serializable private static final char OP_WILDCARD = '*'; private static final char OP_AND = '+'; private static final char OP_NOT = '-'; + private static final String STR_OP_WILDCARD = "" + OP_WILDCARD; /** Search mode constants */ public final static int SEARCH_ALL = 0; @@ -174,21 +175,7 @@ public final class SearchContext implements Serializable nameAttrBuf.append(OP_NOT); } - // simple single word text search - if (text.charAt(0) != OP_WILDCARD) - { - // escape characters and append the wildcard character - String safeText = QueryParser.escape(text); - fullTextBuf.append("TEXT:").append(safeText).append(OP_WILDCARD); - nameAttrBuf.append("@").append(nameAttr).append(":").append(safeText).append(OP_WILDCARD); - } - else - { - // found a leading wildcard - prepend it again after escaping the other characters - String safeText = QueryParser.escape(text.substring(1)); - fullTextBuf.append("TEXT:*").append(safeText).append(OP_WILDCARD); - nameAttrBuf.append("@").append(nameAttr).append(":*").append(safeText).append(OP_WILDCARD); - } + processSearchTextAttribute(nameAttr, text, nameAttrBuf, fullTextBuf); } } else @@ -253,18 +240,8 @@ public final class SearchContext implements Serializable nameAttrBuf.append(OP_AND); } - if (term.charAt(0) != OP_WILDCARD) - { - String safeTerm = QueryParser.escape(term); - fullTextBuf.append("TEXT:").append(safeTerm).append(OP_WILDCARD); - nameAttrBuf.append("@").append(nameAttr).append(":").append(safeTerm).append(OP_WILDCARD); - } - else - { - String safeTerm = QueryParser.escape(term.substring(1)); - fullTextBuf.append("TEXT:*").append(safeTerm).append(OP_WILDCARD); - nameAttrBuf.append("@").append(nameAttr).append(":*").append(safeTerm).append(OP_WILDCARD); - } + processSearchTextAttribute(nameAttr, term, nameAttrBuf, fullTextBuf); + fullTextBuf.append(' '); nameAttrBuf.append(' '); @@ -317,11 +294,9 @@ public final class SearchContext implements Serializable for (QName qname : queryAttributes.keySet()) { String value = queryAttributes.get(qname).trim(); - if (value.length() != 0 && value.length() >= minimum) + if (value.length() >= minimum) { - String escapedName = Repository.escapeQName(qname); - attributeQuery.append(" +@").append(escapedName) - .append(":").append(QueryParser.escape(value)).append(OP_WILDCARD); + processSearchAttribute(qname, value, attributeQuery); } } @@ -480,6 +455,114 @@ public final class SearchContext implements Serializable return query; } + /** + * Build the lucene search terms required for the specified attribute and append to a buffer. + * Supports text values with a wildcard '*' character as the prefix and/or the suffix. + * + * @param qname QName of the attribute + * @param value Non-null value of the attribute + * @param buf Buffer to append lucene terms to + */ + private static void processSearchAttribute(QName qname, String value, StringBuilder buf) + { + if (value.indexOf(' ') == -1) + { + String safeValue; + String prefix = ""; + String suffix = ""; + + // look for a wildcard suffix + if (value.charAt(value.length() - 1) != OP_WILDCARD) + { + // look for wildcard prefix + if (value.charAt(0) != OP_WILDCARD) + { + safeValue = QueryParser.escape(value); + } + else + { + safeValue = QueryParser.escape(value.substring(1)); + prefix = STR_OP_WILDCARD; + } + } + else + { + // found a wildcard suffix - append it again after escaping the other characters + suffix = STR_OP_WILDCARD; + + // look for wildcard prefix + if (value.charAt(0) != OP_WILDCARD) + { + safeValue = QueryParser.escape(value.substring(0, value.length() - 1)); + } + else + { + safeValue = QueryParser.escape(value.substring(1, value.length() - 1)); + prefix = STR_OP_WILDCARD; + } + } + + buf.append(" +@").append(Repository.escapeQName(qname)).append(":") + .append(prefix).append(safeValue).append(suffix); + } + else + { + // phrase multi-word search + String safeValue = QueryParser.escape(value); + buf.append(" +@").append(Repository.escapeQName(qname)).append(":\"").append(safeValue).append('"'); + } + } + + /** + * Build the lucene search terms required for the specified attribute and append to multiple buffers. + * Supports text values with a wildcard '*' character as the prefix and/or the suffix. + * + * @param qname QName.toString() of the attribute + * @param value Non-null value of the attribute + * @param attrBuf Attribute search buffer to append lucene terms to + * @param textBuf Text search buffer to append lucene terms to + */ + private static void processSearchTextAttribute(String qname, String value, StringBuilder attrBuf, StringBuilder textBuf) + { + String safeValue; + String suffix = ""; + String prefix = ""; + + if (value.charAt(value.length() - 1) != OP_WILDCARD) + { + // look for wildcard prefix + if (value.charAt(0) != OP_WILDCARD) + { + safeValue = QueryParser.escape(value); + } + else + { + // found a leading wildcard - prepend it again after escaping the other characters + prefix = STR_OP_WILDCARD; + safeValue = QueryParser.escape(value.substring(1)); + } + } + else + { + suffix = STR_OP_WILDCARD; + + // look for wildcard prefix + if (value.charAt(0) != OP_WILDCARD) + { + safeValue = QueryParser.escape(value.substring(0, value.length() - 1)); + } + else + { + prefix = STR_OP_WILDCARD; + safeValue = QueryParser.escape(value.substring(1, value.length() - 1)); + } + } + + textBuf.append("TEXT:").append(prefix).append(safeValue).append(suffix); + attrBuf.append("@").append(qname).append(":") + .append(prefix).append(safeValue).append(suffix); + } + /** * Generate a search XPATH pointing to the specified node, optionally return an XPATH * that includes the child nodes. diff --git a/source/java/org/alfresco/web/bean/SpaceDetailsBean.java b/source/java/org/alfresco/web/bean/SpaceDetailsBean.java index 39b0793ad3..5e3bc342a0 100644 --- a/source/java/org/alfresco/web/bean/SpaceDetailsBean.java +++ b/source/java/org/alfresco/web/bean/SpaceDetailsBean.java @@ -34,6 +34,7 @@ import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; import org.alfresco.web.app.AlfrescoNavigationHandler; import org.alfresco.web.app.Application; +import org.alfresco.web.app.servlet.GuestTemplateContentServlet; import org.alfresco.web.app.servlet.TemplateContentServlet; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; @@ -506,9 +507,9 @@ public class SpaceDetailsBean extends BaseDetailsBean // build RSS feed template URL from selected template and the space NodeRef and // add the guest=true URL parameter - this is required for no login access and // add the mimetype=text/xml URL parameter - required to return correct stream type - return TemplateContentServlet.generateURL(space.getNodeRef(), + return GuestTemplateContentServlet.generateURL(space.getNodeRef(), (NodeRef)space.getProperties().get(ContentModel.PROP_FEEDTEMPLATE)) - + "/rss.xml?guest=true" + "&mimetype=text%2Fxml"; + + "/rss.xml?mimetype=text%2Fxml"; } /** diff --git a/source/java/org/alfresco/web/bean/dialog/DialogManager.java b/source/java/org/alfresco/web/bean/dialog/DialogManager.java index f4238e9131..272266819e 100644 --- a/source/java/org/alfresco/web/bean/dialog/DialogManager.java +++ b/source/java/org/alfresco/web/bean/dialog/DialogManager.java @@ -71,14 +71,14 @@ public final class DialogManager "' does not implement the required IDialogBean interface"); } + // create the DialogState object + this.currentDialogState = new DialogState(config, dialog); + // initialise the managed bean dialog.init(this.paramsToApply); // reset the current parameters so subsequent dialogs don't get them this.paramsToApply = null; - - // create the DialogState object - this.currentDialogState = new DialogState(config, dialog); } /** diff --git a/source/java/org/alfresco/web/bean/repository/Node.java b/source/java/org/alfresco/web/bean/repository/Node.java index f5e3388f19..c892abaadf 100644 --- a/source/java/org/alfresco/web/bean/repository/Node.java +++ b/source/java/org/alfresco/web/bean/repository/Node.java @@ -89,7 +89,7 @@ public class Node implements Serializable /** * @return All the properties known about this node. */ - public Map getProperties() + public final Map getProperties() { if (this.propsRetrieved == false) { diff --git a/source/java/org/alfresco/web/bean/repository/TransientNode.java b/source/java/org/alfresco/web/bean/repository/TransientNode.java index 9f5332fd8b..fa7ca06c0a 100644 --- a/source/java/org/alfresco/web/bean/repository/TransientNode.java +++ b/source/java/org/alfresco/web/bean/repository/TransientNode.java @@ -70,6 +70,9 @@ public class TransientNode extends Node // setup the transient node so that the super class methods work // and do not need to go back to the repository + if (logger.isDebugEnabled()) + logger.debug("Initialising transient node with data: " + data); + DictionaryService ddService = this.getServiceRegistry().getDictionaryService(); // marshall the given properties and associations into the internal maps @@ -94,25 +97,11 @@ public class TransientNode extends Node { if (assocDef.isChild()) { - // TODO: handle lists of NodeRef's - NodeRef child = null; Object obj = data.get(item); - if (obj instanceof String) - { - child = new NodeRef((String)obj); - } - else if (obj instanceof NodeRef) - { - child = (NodeRef)obj; - } - else if (obj instanceof List) - { - if (logger.isWarnEnabled()) - logger.warn("0..* child associations are not supported yet"); - } - - if (child != null) + if (obj instanceof NodeRef) { + NodeRef child = (NodeRef)obj; + // create a child association reference, add it to a list and add the list // to the list of child associations for this node List assocs = new ArrayList(1); @@ -122,28 +111,36 @@ public class TransientNode extends Node this.childAssociations.put(item, assocs); } + else if (obj instanceof List) + { + List targets = (List)obj; + + List assocs = new ArrayList(targets.size()); + + for (Object target : targets) + { + if (target instanceof NodeRef) + { + NodeRef currentChild = (NodeRef)target; + ChildAssociationRef childRef = new ChildAssociationRef(assocDef.getName(), + this.nodeRef, null, currentChild); + assocs.add(childRef); + } + } + + if (assocs.size() > 0) + { + this.childAssociations.put(item, assocs); + } + } } else { - // TODO: handle lists of NodeRef's - NodeRef target = null; Object obj = data.get(item); - if (obj instanceof String) - { - target = new NodeRef((String)obj); - } - else if (obj instanceof NodeRef) - { - target = (NodeRef)obj; - } - else if (obj instanceof List) - { - if (logger.isWarnEnabled()) - logger.warn("0..* associations are not supported yet"); - } - - if (target != null) + if (obj instanceof NodeRef) { + NodeRef target = (NodeRef)obj; + // create a association reference, add it to a list and add the list // to the list of associations for this node List assocs = new ArrayList(1); @@ -152,6 +149,27 @@ public class TransientNode extends Node this.associations.put(item, assocs); } + else if (obj instanceof List) + { + List targets = (List)obj; + + List assocs = new ArrayList(targets.size()); + + for (Object target : targets) + { + if (target instanceof NodeRef) + { + NodeRef currentTarget = (NodeRef)target; + AssociationRef assocRef = new AssociationRef(this.nodeRef, assocDef.getName(), currentTarget); + assocs.add(assocRef); + } + } + + if (assocs.size() > 0) + { + this.associations.put(item, assocs); + } + } } } } diff --git a/source/java/org/alfresco/web/bean/workflow/ManageTaskDialog.java b/source/java/org/alfresco/web/bean/workflow/ManageTaskDialog.java index 2e63eb4630..04ba84f892 100644 --- a/source/java/org/alfresco/web/bean/workflow/ManageTaskDialog.java +++ b/source/java/org/alfresco/web/bean/workflow/ManageTaskDialog.java @@ -136,7 +136,7 @@ public class ManageTaskDialog extends BaseDialogBean logger.debug("Saving task: " + this.task.id); // prepare the edited parameters for saving - Map params = WorkflowBean.prepareTaskParams(this.taskNode); + Map params = WorkflowUtil.prepareTaskParams(this.taskNode); if (logger.isDebugEnabled()) logger.debug("Saving task with parameters: " + params); @@ -262,7 +262,7 @@ public class ManageTaskDialog extends BaseDialogBean tx.begin(); // prepare the edited parameters for saving - Map params = WorkflowBean.prepareTaskParams(this.taskNode); + Map params = WorkflowUtil.prepareTaskParams(this.taskNode); if (logger.isDebugEnabled()) logger.debug("Transitioning task with parameters: " + params); @@ -399,7 +399,7 @@ public class ManageTaskDialog extends BaseDialogBean */ public void togglePackageItemComplete(ActionEvent event) { - // TODO: implement this! + // TODO: not supported yet } // ------------------------------------------------------------------------------ diff --git a/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java b/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java index 7425da8575..5616f95813 100644 --- a/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java +++ b/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java @@ -119,7 +119,7 @@ public class StartWorkflowWizard extends BaseWizardBean logger.debug("Starting workflow: " + this.selectedWorkflow); // prepare the parameters from the current state of the property sheet - Map params = WorkflowBean.prepareTaskParams(this.startTaskNode); + Map params = WorkflowUtil.prepareTaskParams(this.startTaskNode); if (logger.isDebugEnabled()) logger.debug("Starting workflow with parameters: " + params); diff --git a/source/java/org/alfresco/web/bean/workflow/WorkflowBean.java b/source/java/org/alfresco/web/bean/workflow/WorkflowBean.java index 4e5da783fd..eca548a8ed 100644 --- a/source/java/org/alfresco/web/bean/workflow/WorkflowBean.java +++ b/source/java/org/alfresco/web/bean/workflow/WorkflowBean.java @@ -1,25 +1,19 @@ package org.alfresco.web.bean.workflow; -import java.io.Serializable; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.faces.context.FacesContext; import javax.transaction.UserTransaction; import org.alfresco.model.ContentModel; import org.alfresco.repo.workflow.WorkflowModel; -import org.alfresco.service.cmr.repository.AssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTask; import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition; import org.alfresco.service.cmr.workflow.WorkflowTaskState; import org.alfresco.service.cmr.workflow.WorkflowTransition; -import org.alfresco.service.namespace.QName; import org.alfresco.util.ISO9075; import org.alfresco.web.app.Application; import org.alfresco.web.bean.repository.Node; @@ -31,7 +25,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * Managed bean used for handling workflow related features + * Managed bean used for providing support for the workflow task dashlets * * @author gavinc */ @@ -55,40 +49,43 @@ public class WorkflowBean */ public List getTasksToDo() { - // get the current username - FacesContext context = FacesContext.getCurrentInstance(); - User user = Application.getCurrentUser(context); - String userName = ISO9075.encode(user.getUserName()); - - UserTransaction tx = null; - try + if (this.tasks == null) { - tx = Repository.getUserTransaction(context, true); - tx.begin(); + // get the current username + FacesContext context = FacesContext.getCurrentInstance(); + User user = Application.getCurrentUser(context); + String userName = ISO9075.encode(user.getUserName()); - // get the current in progress tasks for the current user - List tasks = this.workflowService.getAssignedTasks( - userName, WorkflowTaskState.IN_PROGRESS); - - // create a list of transient nodes to represent - this.tasks = new ArrayList(tasks.size()); - for (WorkflowTask task : tasks) + UserTransaction tx = null; + try { - Node node = createTask(task); - this.tasks.add(node); + tx = Repository.getUserTransaction(context, true); + tx.begin(); - if (logger.isDebugEnabled()) - logger.debug("Added to do task: " + node); + // get the current in progress tasks for the current user + List tasks = this.workflowService.getAssignedTasks( + userName, WorkflowTaskState.IN_PROGRESS); + + // create a list of transient nodes to represent + this.tasks = new ArrayList(tasks.size()); + for (WorkflowTask task : tasks) + { + Node node = createTask(task); + this.tasks.add(node); + + if (logger.isDebugEnabled()) + logger.debug("Added to do task: " + node); + } + + // commit the changes + tx.commit(); + } + catch (Throwable e) + { + // rollback the transaction + try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} + Utils.addErrorMessage("Failed to get to do tasks: " + e.toString(), e); } - - // commit the changes - tx.commit(); - } - catch (Throwable e) - { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} - Utils.addErrorMessage("Failed to get to do tasks: " + e.toString(), e); } return this.tasks; @@ -102,40 +99,43 @@ public class WorkflowBean */ public List getTasksCompleted() { - // get the current username - FacesContext context = FacesContext.getCurrentInstance(); - User user = Application.getCurrentUser(context); - String userName = ISO9075.encode(user.getUserName()); - - UserTransaction tx = null; - try + if (this.completedTasks == null) { - tx = Repository.getUserTransaction(context, true); - tx.begin(); + // get the current username + FacesContext context = FacesContext.getCurrentInstance(); + User user = Application.getCurrentUser(context); + String userName = ISO9075.encode(user.getUserName()); - // get the current in progress tasks for the current user - List tasks = this.workflowService.getAssignedTasks( - userName, WorkflowTaskState.COMPLETED); - - // create a list of transient nodes to represent - this.completedTasks = new ArrayList(tasks.size()); - for (WorkflowTask task : tasks) + UserTransaction tx = null; + try { - Node node = createTask(task); - this.completedTasks.add(node); + tx = Repository.getUserTransaction(context, true); + tx.begin(); - if (logger.isDebugEnabled()) - logger.debug("Added completed task: " + node); + // get the current in progress tasks for the current user + List tasks = this.workflowService.getAssignedTasks( + userName, WorkflowTaskState.COMPLETED); + + // create a list of transient nodes to represent + this.completedTasks = new ArrayList(tasks.size()); + for (WorkflowTask task : tasks) + { + Node node = createTask(task); + this.completedTasks.add(node); + + if (logger.isDebugEnabled()) + logger.debug("Added completed task: " + node); + } + + // commit the changes + tx.commit(); } - - // commit the changes - tx.commit(); - } - catch (Throwable e) - { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} - Utils.addErrorMessage("Failed to get completed tasks: " + e.toString(), e); + catch (Throwable e) + { + // rollback the transaction + try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} + Utils.addErrorMessage("Failed to get completed tasks: " + e.toString(), e); + } } return this.completedTasks; @@ -163,47 +163,6 @@ public class WorkflowBean // ------------------------------------------------------------------------------ // Helper methods - - public static Map prepareTaskParams(Node node) - { - Map params = new HashMap(); - - // marshal the properties and associations captured by the property sheet - // back into a Map to pass to the workflow service - - // go through all the properties in the transient node and add them to - // params map - Map props = node.getProperties(); - for (String propName : props.keySet()) - { - QName propQName = Repository.resolveToQName(propName); - params.put(propQName, (Serializable)props.get(propName)); - } - - // go through any associations that have been added to the start task - // and build a list of NodeRefs representing the targets - Map> assocs = node.getAddedAssociations(); - for (String assocName : assocs.keySet()) - { - QName assocQName = Repository.resolveToQName(assocName); - - // get the associations added and create list of targets - Map addedAssocs = assocs.get(assocName); - List targets = new ArrayList(addedAssocs.size()); - for (AssociationRef assoc : addedAssocs.values()) - { - targets.add(assoc.getTargetRef()); - } - - // add the targets for this particular association - if (targets.size() > 0) - { - params.put(assocQName, (Serializable)targets); - } - } - - return params; - } /** * Creates and populates a TransientNode to represent the given @@ -225,15 +184,6 @@ public class WorkflowBean node.getProperties().put("type", taskDef.metadata.getTitle()); node.getProperties().put("id", task.id); - // add the name of the source space (if there is one) - NodeRef context = (NodeRef)task.properties.get(WorkflowModel.PROP_CONTEXT); - if (context != null && this.nodeService.exists(context)) - { - String name = Repository.getNameForNode(this.nodeService, context); - node.getProperties().put("sourceSpaceName", name); - node.getProperties().put("sourceSpaceId", context.getId()); - } - // add extra properties for completed tasks if (task.state.equals(WorkflowTaskState.COMPLETED)) { @@ -260,6 +210,9 @@ public class WorkflowBean // add the workflow instance id and name this taks belongs to node.getProperties().put("workflowInstanceId", task.path.instance.id); + + // add the task itself as a property + node.getProperties().put("workflowTask", task); } return node; diff --git a/source/java/org/alfresco/web/bean/workflow/WorkflowConsoleBean.java b/source/java/org/alfresco/web/bean/workflow/WorkflowConsoleBean.java new file mode 100644 index 0000000000..cdf66e8149 --- /dev/null +++ b/source/java/org/alfresco/web/bean/workflow/WorkflowConsoleBean.java @@ -0,0 +1,184 @@ +/* + * 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. + */ +package org.alfresco.web.bean.workflow; + +import org.alfresco.repo.workflow.WorkflowInterpreter; +import org.alfresco.service.cmr.workflow.WorkflowDefinition; + + +/** + * Backing bean to support the Workflow Console + */ +public class WorkflowConsoleBean +{ + // command + private String command = ""; + private String submittedCommand = "none"; + private long duration = 0L; + private String result = null; + + // supporting repository services + private WorkflowInterpreter workflowInterpreter; + + + /** + * @param nodeService node service + */ + public void setWorkflowInterpreter(WorkflowInterpreter workflowInterpreter) + { + this.workflowInterpreter = workflowInterpreter; + } + + /** + * Gets the command result + * + * @return result + */ + public String getResult() + { + if (result == null) + { + interpretCommand("help"); + } + return result; + } + + /** + * Sets the command result + * + * @param result + */ + public void setResult(String result) + { + this.result = result; + } + + /** + * Gets the current query + * + * @return query statement + */ + public String getCommand() + { + return command; + } + + /** + * Set the current query + * + * @param query query statement + */ + public void setCommand(String command) + { + this.command = command; + } + + /** + * Gets the submitted command + * + * @return submitted command + */ + public String getSubmittedCommand() + { + return submittedCommand; + } + + /** + * Set the current query + * + * @param query query statement + */ + public void setSubmittedCommand(String submittedCommand) + { + this.submittedCommand = submittedCommand; + } + + /** + * Gets the last command duration + * + * @return command duration + */ + public long getDuration() + { + return duration; + } + + /** + * Set the current query + * + * @param query query statement + */ + public void setDuration(long duration) + { + this.duration = duration; + } + + /** + * Action to submit command + * + * @return next action + */ + public String submitCommand() + { + interpretCommand(command); + return "success"; + } + + /** + * Gets the current user name + * + * @return user name + */ + public String getCurrentUserName() + { + return workflowInterpreter.getCurrentUserName(); + } + + /** + * Gets the current workflow definition + * + * @return workflow definition + */ + public String getCurrentWorkflowDef() + { + WorkflowDefinition def = workflowInterpreter.getCurrentWorkflowDef(); + return (def == null) ? "None" : def.title + " v" + def.version; + } + + /** + * Interpret workflow console command + * + * @param command command + */ + private void interpretCommand(String command) + { + try + { + long startms = System.currentTimeMillis(); + String result = workflowInterpreter.interpretCommand(command); + setDuration(System.currentTimeMillis() - startms); + setResult(result); + setCommand(""); + setSubmittedCommand(command); + } + catch (Exception e) + { + setResult(e.toString()); + } + } + +} diff --git a/source/java/org/alfresco/web/bean/WorkflowUtil.java b/source/java/org/alfresco/web/bean/workflow/WorkflowUtil.java similarity index 64% rename from source/java/org/alfresco/web/bean/WorkflowUtil.java rename to source/java/org/alfresco/web/bean/workflow/WorkflowUtil.java index fa57b332d7..2f6412f4e9 100644 --- a/source/java/org/alfresco/web/bean/WorkflowUtil.java +++ b/source/java/org/alfresco/web/bean/workflow/WorkflowUtil.java @@ -14,22 +14,29 @@ * language governing permissions and limitations under the * License. */ -package org.alfresco.web.bean; +package org.alfresco.web.bean.workflow; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.CopyService; 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.web.bean.repository.Node; -import org.apache.log4j.Logger; +import org.alfresco.web.bean.repository.Repository; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** - * Helper class for common Simple Workflow functionality. + * Helper class for common Workflow functionality. *

* This class should be replaced with calls to a WorkflowService once it is available. * @@ -37,7 +44,7 @@ import org.apache.log4j.Logger; */ public class WorkflowUtil { - private static Logger logger = Logger.getLogger(WorkflowUtil.class); + private static Log logger = LogFactory.getLog(WorkflowUtil.class); /** * Execute the Approve step for the Simple Workflow on a node. @@ -139,9 +146,14 @@ public class WorkflowUtil else { // copy the document to the specified folder - String qname = QName.createValidLocalName(docNode.getName()); - copyService.copy(ref, rejectFolder, ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname)); + String name = docNode.getName(); + String qname = QName.createValidLocalName(name); + NodeRef newNode = copyService.copy(ref, rejectFolder, ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname), true); + + // the copy service does not copy the name of the node so we + // need to update the property on the copied item + nodeService.setProperty(newNode, ContentModel.PROP_NAME, name); } if (logger.isDebugEnabled()) @@ -151,4 +163,60 @@ public class WorkflowUtil rejectFolder.getId()); } } + + /** + * Prepares the given node for persistence in the workflow engine. + * + * @param node The node to package up for persistence + * @return The map of data representing the node + */ + public static Map prepareTaskParams(Node node) + { + Map params = new HashMap(); + + // marshal the properties and associations captured by the property sheet + // back into a Map to pass to the workflow service + + // go through all the properties in the transient node and add them to + // params map + Map props = node.getProperties(); + for (String propName : props.keySet()) + { + QName propQName = Repository.resolveToQName(propName); + params.put(propQName, (Serializable)props.get(propName)); + } + + // go through any associations that have been added to the start task + // and build a list of NodeRefs representing the targets + Map> assocs = node.getAddedAssociations(); + for (String assocName : assocs.keySet()) + { + QName assocQName = Repository.resolveToQName(assocName); + + // get the associations added and create list of targets + Map addedAssocs = assocs.get(assocName); + List targets = new ArrayList(addedAssocs.size()); + for (AssociationRef assoc : addedAssocs.values()) + { + targets.add(assoc.getTargetRef()); + } + + // add the targets for this particular association + if (targets.size() > 0) + { + params.put(assocQName, (Serializable)targets); + } + } + + // TODO: Deal with child associations if and when we need to support + // them for workflow tasks, for now warn that they are being used + Map childAssocs = node.getAddedChildAssociations(); + if (childAssocs.size() > 0) + { + if (logger.isWarnEnabled()) + logger.warn("Child associations are present but are not supported for workflow tasks, ignoring..."); + } + + return params; + } } diff --git a/source/java/org/alfresco/web/config/ClientConfigElement.java b/source/java/org/alfresco/web/config/ClientConfigElement.java index eba6408ad9..e8a384439f 100644 --- a/source/java/org/alfresco/web/config/ClientConfigElement.java +++ b/source/java/org/alfresco/web/config/ClientConfigElement.java @@ -36,13 +36,19 @@ public class ClientConfigElement extends ConfigElementAdapter private int searchMinimum = 3; private boolean forceAndTerms = false; private int searchMaxResults = -1; + private int selectorsSearchMaxResults = 500; private String helpUrl = null; private String editLinkType = "http"; private String homeSpacePermission = null; +<<<<<<< .working private boolean ajaxEnabled = false; private String initialLocation = "myalfresco"; private String wcmDomain = null; private String wcmPort = null; +======= + private boolean ajaxEnabled = false; + private String initialLocation = "myalfresco"; +>>>>>>> .merge-right.r4305 /** * Default Constructor @@ -137,17 +143,34 @@ public class ClientConfigElement extends ConfigElementAdapter combinedElement.setSearchMaxResults(newElement.getSearchMaxResults()); } +<<<<<<< .working if (newElement.isShelfVisible() != combinedElement.isShelfVisible()) +======= + if (newElement.getSelectorsSearchMaxResults() != combinedElement.getSelectorsSearchMaxResults()) +>>>>>>> .merge-right.r4305 { +<<<<<<< .working combinedElement.setShelfVisible(newElement.isShelfVisible()); +======= + combinedElement.setSelectorsSearchMaxResults(newElement.getSelectorsSearchMaxResults()); +>>>>>>> .merge-right.r4305 } +<<<<<<< .working if (newElement.getFromEmailAddress() != null && (newElement.getFromEmailAddress().equals(combinedElement.getFromEmailAddress()) == false)) +======= + if (newElement.isShelfVisible() != combinedElement.isShelfVisible()) +>>>>>>> .merge-right.r4305 { +<<<<<<< .working combinedElement.setFromEmailAddress(newElement.getFromEmailAddress()); +======= + combinedElement.setShelfVisible(newElement.isShelfVisible()); +>>>>>>> .merge-right.r4305 } +<<<<<<< .working if (newElement.isAjaxEnabled() != combinedElement.isAjaxEnabled()) { combinedElement.setAjaxEnabled(newElement.isAjaxEnabled()); @@ -178,6 +201,26 @@ public class ClientConfigElement extends ConfigElementAdapter } return combinedElement; +======= + if (newElement.getFromEmailAddress() != null && + (newElement.getFromEmailAddress().equals(combinedElement.getFromEmailAddress()) == false)) + { + combinedElement.setFromEmailAddress(newElement.getFromEmailAddress()); + } + + if (newElement.isAjaxEnabled() != combinedElement.isAjaxEnabled()) + { + combinedElement.setAjaxEnabled(newElement.isAjaxEnabled()); + } + + if (newElement.getInitialLocation() != null && + newElement.getInitialLocation().equals(combinedElement.getInitialLocation()) == false) + { + combinedElement.setInitialLocation(newElement.getInitialLocation()); + } + + return combinedElement; +>>>>>>> .merge-right.r4305 } /** @@ -330,10 +373,9 @@ public class ClientConfigElement extends ConfigElementAdapter * * @return */ - public int getSearchMaxResults() { - return searchMaxResults; + return this.searchMaxResults; } /** @@ -346,6 +388,29 @@ public class ClientConfigElement extends ConfigElementAdapter { this.searchMaxResults = searchMaxResults; } + + /** + * If positive, this will limit the size of the result set from the search + * used in selector components. + * + * @return The maximum number of results to display + */ + public int getSelectorsSearchMaxResults() + { + return this.selectorsSearchMaxResults; + } + + /** + * Set if the the result set from a search for the selector components + * will be of limited size. If negative it is unlimited, by default, + * this is set to 500. + * + * @param selectorsSearchMaxResults + */ + /*package*/ void setSelectorsSearchMaxResults(int selectorsSearchMaxResults) + { + this.selectorsSearchMaxResults = selectorsSearchMaxResults; + } /** * @return Returns the default Home Space permissions. @@ -362,6 +427,7 @@ public class ClientConfigElement extends ConfigElementAdapter { this.homeSpacePermission = homeSpacePermission; } +<<<<<<< .working /** * @return Returns whether AJAX support is enabled in the client @@ -428,4 +494,40 @@ public class ClientConfigElement extends ConfigElementAdapter { this.wcmPort = wcmPort; } +======= + + /** + * @return Returns whether AJAX support is enabled in the client + */ + public boolean isAjaxEnabled() + { + return this.ajaxEnabled; + } + + /** + * Sets whether AJAX support is enabled in the client + * + * @param ajaxEnabled + */ + /*package*/ void setAjaxEnabled(boolean ajaxEnabled) + { + this.ajaxEnabled = ajaxEnabled; + } + + /** + * @return Returns the default initial location for the user. + */ + public String getInitialLocation() + { + return this.initialLocation; + } + + /** + * @param initialLocation The initial location to set. + */ + /*package*/ void setInitialLocation(String initialLocation) + { + this.initialLocation = initialLocation; + } +>>>>>>> .merge-right.r4305 } diff --git a/source/java/org/alfresco/web/config/ClientElementReader.java b/source/java/org/alfresco/web/config/ClientElementReader.java index 593112d366..9b6d81e7ea 100644 --- a/source/java/org/alfresco/web/config/ClientElementReader.java +++ b/source/java/org/alfresco/web/config/ClientElementReader.java @@ -36,6 +36,7 @@ public class ClientElementReader implements ConfigElementReader public static final String ELEMENT_SEARCHMINIMUM = "search-minimum"; public static final String ELEMENT_SEARCHANDTERMS = "search-and-terms"; public static final String ELEMENT_SEARCHMAXRESULTS = "search-max-results"; + public static final String ELEMENT_SELECTORSSEARCHMAXRESULTS = "selectors-search-max-results"; public static final String ELEMENT_HOMESPACEPERMISSION = "home-space-permission"; public static final String ELEMENT_FROMEMAILADDRESS = "from-email-address"; public static final String ELEMENT_SHELFVISIBLE = "shelf-visible"; @@ -113,6 +114,14 @@ public class ClientElementReader implements ConfigElementReader configElement.setSearchMaxResults(Integer.parseInt(searchMaxResults.getTextTrim())); } + // get the selectors search max results size + Element selectorsSearchMaxResults = element.element(ELEMENT_SELECTORSSEARCHMAXRESULTS); + if (selectorsSearchMaxResults != null) + { + configElement.setSelectorsSearchMaxResults( + Integer.parseInt(selectorsSearchMaxResults.getTextTrim())); + } + // get the default permission for newly created users Home Spaces Element permission = element.element(ELEMENT_HOMESPACEPERMISSION); if (permission != null) diff --git a/source/java/org/alfresco/web/ui/common/renderer/DatePickerRenderer.java b/source/java/org/alfresco/web/ui/common/renderer/DatePickerRenderer.java index d9458bd107..26196fb2c0 100644 --- a/source/java/org/alfresco/web/ui/common/renderer/DatePickerRenderer.java +++ b/source/java/org/alfresco/web/ui/common/renderer/DatePickerRenderer.java @@ -37,8 +37,6 @@ import javax.faces.model.SelectItem; import org.alfresco.web.app.Application; import org.alfresco.web.ui.common.Utils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * @author kevinr @@ -58,8 +56,6 @@ public class DatePickerRenderer extends BaseRenderer private static final int CMD_SET = 1; private static final int CMD_RESET = 2; private static final int CMD_TODAY = 3; - - private static final Log logger = LogFactory.getLog(DatePickerRenderer.class); /** * @see javax.faces.render.Renderer#decode(javax.faces.context.FacesContext, javax.faces.component.UIComponent) diff --git a/source/java/org/alfresco/web/ui/repo/component/UIContentSelector.java b/source/java/org/alfresco/web/ui/repo/component/UIContentSelector.java index 2aeec8d7a4..de99c00fab 100644 --- a/source/java/org/alfresco/web/ui/repo/component/UIContentSelector.java +++ b/source/java/org/alfresco/web/ui/repo/component/UIContentSelector.java @@ -30,7 +30,9 @@ import javax.faces.el.ValueBinding; import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.LimitBy; import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; @@ -353,15 +355,30 @@ public class UIContentSelector extends UIInput query.append(":*" + safeContains + "*"); } + + int maxResults = Application.getClientConfig(context).getSelectorsSearchMaxResults(); if (logger.isDebugEnabled()) + { logger.debug("Query: " + query.toString()); + logger.debug("Max results size: " + maxResults); + } + + // setup search parameters, including limiting the results + SearchParameters searchParams = new SearchParameters(); + searchParams.addStore(Repository.getStoreRef()); + searchParams.setLanguage(SearchService.LANGUAGE_LUCENE); + searchParams.setQuery(query.toString()); + if (maxResults > 0) + { + searchParams.setLimit(maxResults); + searchParams.setLimitBy(LimitBy.FINAL_SIZE); + } ResultSet results = null; try { - results = Repository.getServiceRegistry(context).getSearchService().query( - Repository.getStoreRef(), SearchService.LANGUAGE_LUCENE, query.toString()); + results = Repository.getServiceRegistry(context).getSearchService().query(searchParams); this.availableOptions = results.getNodeRefs(); } finally diff --git a/source/java/org/alfresco/web/ui/repo/component/property/BaseAssociationEditor.java b/source/java/org/alfresco/web/ui/repo/component/property/BaseAssociationEditor.java index 3cf4ac6590..4596af1a5d 100644 --- a/source/java/org/alfresco/web/ui/repo/component/property/BaseAssociationEditor.java +++ b/source/java/org/alfresco/web/ui/repo/component/property/BaseAssociationEditor.java @@ -36,6 +36,7 @@ import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.LimitBy; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; @@ -914,8 +915,31 @@ public abstract class BaseAssociationEditor extends UIInput } } + int maxResults = Application.getClientConfig(context).getSelectorsSearchMaxResults(); + if (logger.isDebugEnabled()) + { logger.debug("Query: " + query.toString()); + logger.debug("Max results size: " + maxResults); + } + + SearchParameters searchParams = new SearchParameters(); + searchParams.addStore(Repository.getStoreRef()); + searchParams.setLanguage(SearchService.LANGUAGE_LUCENE); + searchParams.setQuery(query.toString()); + if (maxResults > 0) + { + searchParams.setLimit(maxResults); + searchParams.setLimitBy(LimitBy.FINAL_SIZE); + } + + if (type.equals(ContentModel.TYPE_PERSON.toString())) + { + searchParams.addSort("@" + ContentModel.PROP_LASTNAME, true); + + if (logger.isDebugEnabled()) + logger.debug("Added lastname as sort column to query for people"); + } SearchParameters searchParams = new SearchParameters(); searchParams.addStore(Repository.getStoreRef()); diff --git a/source/java/org/alfresco/web/ui/repo/component/property/UIProperty.java b/source/java/org/alfresco/web/ui/repo/component/property/UIProperty.java index d6b4b7c09c..b3677bbf73 100644 --- a/source/java/org/alfresco/web/ui/repo/component/property/UIProperty.java +++ b/source/java/org/alfresco/web/ui/repo/component/property/UIProperty.java @@ -176,10 +176,11 @@ public class UIProperty extends PropertySheetItem // if we're in edit mode ensure that we don't allow editing of system properties or scenarios we don't support if (propSheet.inEditMode()) { - // if we are trying to edit a NodeRef or Path property type set it to read-only as - // these are internal properties that shouldn't be edited. + // if we are trying to edit a system property type set it to read-only as these are internal + // properties that shouldn't be edited. if (typeName.equals(DataTypeDefinition.NODE_REF) || typeName.equals(DataTypeDefinition.PATH) || - typeName.equals(DataTypeDefinition.CONTENT)) + typeName.equals(DataTypeDefinition.CONTENT) || typeName.equals(DataTypeDefinition.QNAME) || + typeName.equals(DataTypeDefinition.CHILD_ASSOC_REF) || typeName.equals(DataTypeDefinition.ASSOC_REF)) { logger.warn("Setting property " + propDef.getName().toString() + " to read-only as it can not be edited"); control.getAttributes().put("disabled", Boolean.TRUE); diff --git a/source/java/org/alfresco/web/ui/repo/tag/JBPMProcessImageTag.java b/source/java/org/alfresco/web/ui/repo/tag/JBPMProcessImageTag.java new file mode 100644 index 0000000000..90faf788e8 --- /dev/null +++ b/source/java/org/alfresco/web/ui/repo/tag/JBPMProcessImageTag.java @@ -0,0 +1,254 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2005, JBoss Inc., and individual contributors as indicated + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This 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 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.alfresco.web.ui.repo.tag; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspWriter; +import javax.servlet.jsp.tagext.TagSupport; + +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.dom4j.XPath; +import org.dom4j.xpath.DefaultXPath; +import org.jbpm.JbpmContext; +import org.jbpm.file.def.FileDefinition; +import org.jbpm.graph.def.ProcessDefinition; +import org.jbpm.graph.exe.Token; +import org.jbpm.taskmgmt.exe.TaskInstance; + + +// +// +// TODO: DC - Tidy up +// +// + + + + +public class JBPMProcessImageTag extends TagSupport { + + private static final long serialVersionUID = 1L; + private long taskInstanceId = -1; + private long tokenInstanceId = -1; + + private byte[] gpdBytes = null; + private byte[] imageBytes = null; + private Token currentToken = null; + private ProcessDefinition processDefinition = null; + + static String currentTokenColor = "red"; + static String childTokenColor = "blue"; + static String tokenNameColor = "blue"; + + + public void release() { + taskInstanceId = -1; + gpdBytes = null; + imageBytes = null; + currentToken = null; + } + + public int doEndTag() throws JspException { + try { + initialize(); + retrieveByteArrays(); + if (gpdBytes != null && imageBytes != null) { + writeTable(); + } + } catch (IOException e) { + e.printStackTrace(); + throw new JspException("table couldn't be displayed", e); + } catch (DocumentException e) { + e.printStackTrace(); + throw new JspException("table couldn't be displayed", e); + } + release(); + return EVAL_PAGE; + } + + private void retrieveByteArrays() { + try { + FileDefinition fileDefinition = processDefinition.getFileDefinition(); + gpdBytes = fileDefinition.getBytes("gpd.xml"); + imageBytes = fileDefinition.getBytes("processimage.jpg"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void writeTable() throws IOException, DocumentException { + + int borderWidth = 4; + Element rootDiagramElement = DocumentHelper.parseText(new String(gpdBytes)).getRootElement(); + int[] boxConstraint; + int[] imageDimension = extractImageDimension(rootDiagramElement); + String imageLink = "/alfresco/processimage?definitionId=" + processDefinition.getId(); + JspWriter jspOut = pageContext.getOut(); + + if (tokenInstanceId > 0) { + + List allTokens = new ArrayList(); + walkTokens(currentToken, allTokens); + + jspOut.println("

"); + + for (int i = 0; i < allTokens.size(); i++) + { + Token token = (Token) allTokens.get(i); + + //check how many tokens are on teh same level (= having the same parent) + int offset = i; + if(i > 0) { + while(offset > 0 && ((Token) allTokens.get(offset - 1)).getParent().equals(token.getParent())) { + offset--; + } + } + boxConstraint = extractBoxConstraint(rootDiagramElement, token); + + //Adjust for borders + //boxConstraint[2]-=borderWidth*2; + //boxConstraint[3]-=borderWidth*2; + + jspOut.println("
"); + + if(token.getName()!=null) + { + jspOut.println(" " + token.getName() +""); + } + + jspOut.println("
"); + } + jspOut.println("
"); + } + else + { + boxConstraint = extractBoxConstraint(rootDiagramElement); + + jspOut.println(""); + jspOut.println(" "); + jspOut.println(" "); + jspOut.println(" "); + jspOut.println("
"); + jspOut.println(" "); + jspOut.println(" "); + jspOut.println(" "); + jspOut.println(" "); + jspOut.println(" "); + jspOut.println(" "); + jspOut.println(" "); + jspOut.println(" "); + jspOut.println("
 
"); + jspOut.println("
"); + } + } + + private int[] extractBoxConstraint(Element root) { + int[] result = new int[4]; + String nodeName = currentToken.getNode().getName(); + XPath xPath = new DefaultXPath("//node[@name='" + nodeName + "']"); + Element node = (Element) xPath.selectSingleNode(root); + result[0] = Integer.valueOf(node.attribute("x").getValue()).intValue(); + result[1] = Integer.valueOf(node.attribute("y").getValue()).intValue(); + result[2] = Integer.valueOf(node.attribute("width").getValue()).intValue(); + result[3] = Integer.valueOf(node.attribute("height").getValue()).intValue(); + return result; + } + + private int[] extractBoxConstraint(Element root, Token token) { + int[] result = new int[4]; + String nodeName = token.getNode().getName(); + XPath xPath = new DefaultXPath("//node[@name='" + nodeName + "']"); + Element node = (Element) xPath.selectSingleNode(root); + result[0] = Integer.valueOf(node.attribute("x").getValue()).intValue(); + result[1] = Integer.valueOf(node.attribute("y").getValue()).intValue(); + result[2] = Integer.valueOf(node.attribute("width").getValue()).intValue(); + result[3] = Integer.valueOf(node.attribute("height").getValue()).intValue(); + return result; + } + + private int[] extractImageDimension(Element root) { + int[] result = new int[2]; + result[0] = Integer.valueOf(root.attribute("width").getValue()).intValue(); + result[1] = Integer.valueOf(root.attribute("height").getValue()).intValue(); + return result; + } + + private void initialize() { + JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext(); + if (this.taskInstanceId > 0) { + TaskInstance taskInstance = jbpmContext.getTaskMgmtSession().loadTaskInstance(taskInstanceId); + currentToken = taskInstance.getToken(); + } + else + { + if (this.tokenInstanceId > 0) + currentToken = jbpmContext.getGraphSession().loadToken(this.tokenInstanceId); + } + processDefinition = currentToken.getProcessInstance().getProcessDefinition(); + } + + private void walkTokens(Token parent, List allTokens) + { + Map children = parent.getChildren(); + if(children != null && children.size() > 0) + { + Collection childTokens = children.values(); + for (Iterator iterator = childTokens.iterator(); iterator.hasNext();) + { + Token child = (Token) iterator.next(); + walkTokens(child, allTokens); + } + } + + allTokens.add(parent); + } + + public void setTask(long id) { + this.taskInstanceId = id; + } + + public void setToken(long id) { + this.tokenInstanceId = id; + } + +} diff --git a/source/java/org/alfresco/web/ui/repo/tag/PageTag.java b/source/java/org/alfresco/web/ui/repo/tag/PageTag.java index 633258fcff..d94d7a7eab 100644 --- a/source/java/org/alfresco/web/ui/repo/tag/PageTag.java +++ b/source/java/org/alfresco/web/ui/repo/tag/PageTag.java @@ -47,7 +47,7 @@ public class PageTag extends TagSupport */ private final static String ALF_URL = "http://www.alfresco.com"; - private final static String ALF_LOGO = "http://www.alfresco.com/images/alfresco_community_horizont.gif"; + private final static String ALF_LOGO = "http://www.alfresco.com/images/alfresco_community_horiz14.gif"; private final static String SF_LOGO = "/images/logo/sflogo.php.png"; private final static String ALF_TEXT = "Alfresco Community"; private final static String ALF_COPY = "Supplied free of charge with " + diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml index ca01284f82..85c2f87319 100644 --- a/source/web/WEB-INF/faces-config-beans.xml +++ b/source/web/WEB-INF/faces-config-beans.xml @@ -1952,7 +1952,7 @@ WorkflowBean org.alfresco.web.bean.workflow.WorkflowBean - session + request nodeService #{NodeService} @@ -1962,6 +1962,18 @@ #{WorkflowService} + + + + Backing bean used for the Workflow Console + WorkflowConsoleBean + org.alfresco.web.bean.workflow.WorkflowConsoleBean + session + + workflowInterpreter + #{workflowInterpreter} + + @@ -2790,3 +2802,4 @@ session + diff --git a/source/web/WEB-INF/faces-config-navigation.xml b/source/web/WEB-INF/faces-config-navigation.xml index bff45ad3f5..d8d72340f1 100644 --- a/source/web/WEB-INF/faces-config-navigation.xml +++ b/source/web/WEB-INF/faces-config-navigation.xml @@ -1,3 +1,4 @@ +<<<<<<< .working @@ -943,3 +944,892 @@ +======= + + + + + + + + + + The decision rule used by the NavigationHandler to + determine which view must be displayed after the + current view, login.jsp is processed. + + /jsp/login.jsp + + + Indicates to the NavigationHandler that the browse.jsp + view must be displayed if the Action referenced by a + UICommand component on the login.jsp view returns + the outcome "success". + + success + /jsp/browse/browse.jsp + + + + + + /jsp/* + + browse + /jsp/browse/browse.jsp + + + myalfresco + /jsp/dashboards/container.jsp + + + about + /jsp/dialog/about.jsp + + + + + + /jsp/* + + showDocDetails + /jsp/dialog/document-details.jsp + + + showSpaceDetails + /jsp/dialog/space-details.jsp + + + dashboard + /jsp/browse/dashboard.jsp + + + addContent + /jsp/content/add-content-dialog.jsp + + + + + + /jsp/* + + advSearch + /jsp/dialog/advanced-search.jsp + + + + + + /jsp/* + + logout + /jsp/login.jsp + + + relogin + /jsp/relogin.jsp + + + + + + /jsp/* + + adminConsole + /jsp/admin/admin-console.jsp + + + userConsole + /jsp/users/user-console.jsp + + + + + + /jsp/* + + checkoutFile + /jsp/dialog/checkout-file.jsp + + + checkinFile + /jsp/dialog/checkin-file.jsp + + + undoCheckoutFile + /jsp/dialog/undocheckout-file.jsp + + + updateFile + /jsp/dialog/update-file.jsp + + + editFile + /jsp/dialog/edit-file.jsp + + + editHtmlInline + /jsp/dialog/edit-html-inline.jsp + + + editTextInline + /jsp/dialog/edit-text-inline.jsp + + + + + + /jsp/browse/browse.jsp + + + + manageInvitedUsers + /jsp/roles/manage-invited-users.jsp + + + manageContentUsers + /jsp/roles/manage-content-users.jsp + + + manageRules + /jsp/dialog/rules.jsp + + + previewContent + /jsp/dialog/preview-file.jsp + + + previewSpace + /jsp/dialog/preview-space.jsp + + + startDiscussion + /jsp/forums/create-topic.jsp + + + showForum + /jsp/forums/forum.jsp + + + showTopic + /jsp/forums/topic.jsp + + + saveNewSearch + /jsp/dialog/save-search.jsp + + + saveEditSearch + /jsp/dialog/edit-search.jsp + + + manageDeletedItems + /jsp/trashcan/trash-list.jsp + + + + + /jsp/content/add-content-dialog.jsp + + cancel + /jsp/browse/browse.jsp + + + + + + /jsp/admin/admin-console.jsp + + manageCategories + /jsp/categories/categories.jsp + + + manageUsers + /jsp/users/users.jsp + + + manageGroups + /jsp/groups/groups.jsp + + + showSystemInfo + /jsp/dialog/system-info.jsp + + + showNodeBrowser + /jsp/admin/store-browser.jsp + + + import + /jsp/dialog/import.jsp + + + export + /jsp/dialog/export.jsp + + + + + /jsp/dialog/edit-file.jsp + + checkoutFile + /jsp/dialog/checkout-file.jsp + + + + + /jsp/dialog/edit-text-inline.jsp + + checkoutFile + /jsp/dialog/checkout-file.jsp + + + + + /jsp/dialog/edit-html-inline.jsp + + checkoutFile + /jsp/dialog/checkout-file.jsp + + + + + /jsp/dialog/checkout-file.jsp + + checkoutFileLink + /jsp/dialog/checkout-file-link.jsp + + + + + /jsp/dialog/space-details.jsp + + manageInvitedUsers + /jsp/roles/manage-invited-users.jsp + + + manageRules + /jsp/dialog/rules.jsp + + + import + /jsp/dialog/import.jsp + + + export + /jsp/dialog/export.jsp + + + applyTemplate + /jsp/dialog/apply-space-template.jsp + + + applyRSSTemplate + /jsp/dialog/apply-rss-template.jsp + + + previewSpace + /jsp/dialog/preview-space.jsp + + + showForum + /jsp/forums/forum.jsp + + + editCategories + /jsp/dialog/edit-space-category.jsp + + + editSimpleWorkflow + /jsp/dialog/edit-space-simple-workflow.jsp + + + + + /jsp/dialog/apply-rss-template.jsp + + manageInvitedUsers + /jsp/roles/manage-invited-users.jsp + + + + + /jsp/dialog/document-details.jsp + + editSimpleWorkflow + /jsp/dialog/edit-simple-workflow.jsp + + + editCategories + /jsp/dialog/edit-category.jsp + + + previewContent + /jsp/dialog/preview-file.jsp + + + showForum + /jsp/forums/forum.jsp + + + manageContentUsers + /jsp/roles/manage-content-users.jsp + + + applyTemplate + /jsp/dialog/apply-doc-template.jsp + + + + + /jsp/dialog/edit-simple-workflow.jsp + + cancel + /jsp/dialog/document-details.jsp + + + finish + /jsp/dialog/document-details.jsp + + + + + /jsp/dialog/edit-space-simple-workflow.jsp + + cancel + /jsp/dialog/space-details.jsp + + + finish + /jsp/dialog/space-details.jsp + + + + + /jsp/dialog/edit-category.jsp + + cancel + /jsp/dialog/document-details.jsp + + + finish + /jsp/dialog/document-details.jsp + + + + + /jsp/dialog/edit-space-category.jsp + + cancel + /jsp/dialog/space-details.jsp + + + finish + /jsp/dialog/space-details.jsp + + + + + /jsp/dialog/rules.jsp + + deleteRule + /jsp/dialog/delete-rule.jsp + + + + + /jsp/dialog/delete-rule.jsp + + manageRules + /jsp/dialog/rules.jsp + + + cancel + /jsp/dialog/rules.jsp + + + browse + /jsp/dialog/rules.jsp + + + + + + /jsp/dialog/filelink-details.jsp + + editLinkProperties + /jsp/dialog/edit-link-properties.jsp + + + manageContentUsers + /jsp/roles/manage-content-users.jsp + + + + + + /jsp/dialog/spacelink-details.jsp + + editLinkProperties + /jsp/dialog/edit-link-properties.jsp + + + manageContentUsers + /jsp/roles/manage-content-users.jsp + + + + + + /jsp/dialog/edit-link-properties.jsp + + cancelEdit + /jsp/dialog/filelink-details.jsp + + + finishEdit + /jsp/dialog/filelink-details.jsp + + + + + + /jsp/roles/manage-invited-users.jsp + + inviteUsers + /jsp/wizard/invite-users/invite.jsp + + + editRoles + /jsp/roles/edit-user-roles.jsp + + + removeUser + /jsp/roles/remove-invited-user.jsp + + + + + /jsp/roles/edit-user-roles.jsp + + cancel + /jsp/roles/manage-invited-users.jsp + + + finish + /jsp/roles/manage-invited-users.jsp + + + + + /jsp/roles/remove-invited-user.jsp + + cancel + /jsp/roles/manage-invited-users.jsp + + + finish + /jsp/roles/manage-invited-users.jsp + + + + + /jsp/roles/manage-content-users.jsp + + inviteUsers + /jsp/wizard/invite-content-users/invite.jsp + + + editRoles + /jsp/roles/edit-content-user-roles.jsp + + + removeUser + /jsp/roles/remove-content-user.jsp + + + + + /jsp/roles/edit-content-user-roles.jsp + + cancel + /jsp/roles/manage-content-users.jsp + + + finish + /jsp/roles/manage-content-users.jsp + + + + + /jsp/roles/remove-content-user.jsp + + cancel + /jsp/roles/manage-content-users.jsp + + + finish + /jsp/roles/manage-content-users.jsp + + + + + + /jsp/wizard/invite-users/* + + invite + /jsp/wizard/invite-users/invite.jsp + + + notify + /jsp/wizard/invite-users/notify.jsp + + + cancel + /jsp/roles/manage-invited-users.jsp + + + finish + /jsp/roles/manage-invited-users.jsp + + + + + + /jsp/wizard/invite-content-users/* + + invite + /jsp/wizard/invite-content-users/invite.jsp + + + notify + /jsp/wizard/invite-content-users/notify.jsp + + + cancel + /jsp/roles/manage-content-users.jsp + + + finish + /jsp/roles/manage-content-users.jsp + + + + + + /jsp/users/* + + manageUsers + /jsp/users/users.jsp + + + cancel + /jsp/users/users.jsp + + + + + /jsp/users/users.jsp + + createUser + /jsp/wizard/new-user/person-properties.jsp + + + editUser + /jsp/wizard/new-user/person-properties.jsp + + + deleteUser + /jsp/users/delete-user.jsp + + + changePassword + /jsp/users/change-password.jsp + + + + + + /jsp/users/user-console.jsp + + changePassword + /jsp/users/change-my-password.jsp + + + editUserDetails + /jsp/users/edit-user-details.jsp + + + + + + /jsp/wizard/new-user/* + + cancel + /jsp/users/users.jsp + + + finish + /jsp/users/users.jsp + + + person-properties + /jsp/wizard/new-user/person-properties.jsp + + + user-properties + /jsp/wizard/new-user/user-properties.jsp + + + summary + /jsp/wizard/new-user/summary.jsp + + + + + + /jsp/groups/* + + newGroup + /jsp/groups/new-group.jsp + + + deleteGroup + /jsp/groups/delete-group.jsp + + + addUser + /jsp/groups/add-user.jsp + + + deleteUser + /jsp/groups/delete-user.jsp + + + finish + /jsp/groups/groups.jsp + + + cancel + /jsp/groups/groups.jsp + + + + + + /jsp/categories/* + + addCategory + /jsp/categories/new-category.jsp + + + editCategory + /jsp/categories/edit-category.jsp + + + deleteCategory + /jsp/categories/delete-category.jsp + + + finish + /jsp/categories/categories.jsp + + + cancel + /jsp/categories/categories.jsp + + + + + + /jsp/wizard/* + + cancel + /jsp/browse/browse.jsp + + + finish + /jsp/browse/browse.jsp + + + + + + /jsp/admin/* + + #{AdminNodeBrowseBean.selectStores} + success + /jsp/admin/store-browser.jsp + + + nodeBrowser + /jsp/admin/node-browser.jsp + + + + + /jsp/admin/store-browser.jsp + + #{AdminNodeBrowseBean.selectStore} + success + /jsp/admin/node-browser.jsp + + + + + /jsp/admin/node-browser.jsp + + #{AdminNodeBrowseBean.selectChild} + success + /jsp/admin/node-browser.jsp + + + #{AdminNodeBrowseBean.selectPrimaryPath} + success + /jsp/admin/node-browser.jsp + + + #{AdminNodeBrowseBean.selectPrimaryParent} + success + /jsp/admin/node-browser.jsp + + + #{AdminNodeBrowseBean.selectParent} + success + /jsp/admin/node-browser.jsp + + + #{AdminNodeBrowseBean.selectToNode} + success + /jsp/admin/node-browser.jsp + + + #{AdminNodeBrowseBean.selectNodeProperty} + success + /jsp/admin/node-browser.jsp + + + #{AdminNodeBrowseBean.submitSearch} + error + /jsp/admin/node-browser.jsp + + + #{AdminNodeBrowseBean.submitSearch} + node + /jsp/admin/node-browser.jsp + + + #{AdminNodeBrowseBean.submitSearch} + search + /jsp/admin/search-results.jsp + + + + + /jsp/admin/search-results.jsp + + #{AdminNodeBrowseBean.selectResultNode} + success + /jsp/admin/node-browser.jsp + + + + + + /jsp/workflow/workflow-console.jsp + + #{WorkflowConsoleBean.submitCommand} + success + /jsp/workflow/workflow-console.jsp + + + + + + /jsp/forums/* + + + + showForumsDetails + /jsp/forums/forums-details.jsp + + + showForumDetails + /jsp/forums/forum-details.jsp + + + showTopicDetails + /jsp/forums/topic-details.jsp + + + manageInvitedUsers + /jsp/roles/manage-invited-users.jsp + + + import + /jsp/dialog/import.jsp + + + export + /jsp/dialog/export.jsp + + + + + + /jsp/trashcan/* + + deleteItem + /jsp/trashcan/delete-item.jsp + + + recoverItem + /jsp/trashcan/recover-item.jsp + + + recoverAllItems + /jsp/trashcan/recover-all.jsp + + + deleteAllItems + /jsp/trashcan/delete-all.jsp + + + recoverListedItems + /jsp/trashcan/recover-listed.jsp + + + deleteListedItems + /jsp/trashcan/delete-listed.jsp + + + itemDetails + /jsp/trashcan/item-details.jsp + + + recoveryReport + /jsp/trashcan/recovery-report.jsp + + + + + /jsp/dialog/container.jsp + + + + forumsDeleted + /jsp/forums/forums.jsp + + + forumDeleted + /jsp/forums/forums.jsp + + + topicDeleted + /jsp/forums/forum.jsp + + + + +>>>>>>> .merge-right.r4305 diff --git a/source/web/WEB-INF/faces-config-repo.xml b/source/web/WEB-INF/faces-config-repo.xml index a798a656ee..d8f8d9c2f7 100644 --- a/source/web/WEB-INF/faces-config-repo.xml +++ b/source/web/WEB-INF/faces-config-repo.xml @@ -1,3 +1,4 @@ +<<<<<<< .working @@ -228,3 +229,235 @@ +======= + + + + + + + org.alfresco.faces.PropertySheet + org.alfresco.web.ui.repo.component.property.UIPropertySheet + + + + org.alfresco.faces.Property + org.alfresco.web.ui.repo.component.property.UIProperty + + + + org.alfresco.faces.Separator + org.alfresco.web.ui.repo.component.property.UISeparator + + + + org.alfresco.faces.Association + org.alfresco.web.ui.repo.component.property.UIAssociation + + + + org.alfresco.faces.AssociationEditor + org.alfresco.web.ui.repo.component.property.UIAssociationEditor + + + + org.alfresco.faces.ChildAssociation + org.alfresco.web.ui.repo.component.property.UIChildAssociation + + + + org.alfresco.faces.ChildAssociationEditor + org.alfresco.web.ui.repo.component.property.UIChildAssociationEditor + + + + org.alfresco.faces.NodeDescendants + org.alfresco.web.ui.repo.component.UINodeDescendants + + + + org.alfresco.faces.NodePath + org.alfresco.web.ui.repo.component.UINodePath + + + + org.alfresco.faces.SpaceSelector + org.alfresco.web.ui.repo.component.UISpaceSelector + + + + org.alfresco.faces.ContentSelector + org.alfresco.web.ui.repo.component.UIContentSelector + + + + org.alfresco.faces.CategorySelector + org.alfresco.web.ui.repo.component.UICategorySelector + + + + org.alfresco.faces.MimeTypeSelector + org.alfresco.web.ui.repo.component.UIMimeTypeSelector + + + + org.alfresco.faces.SimpleSearch + org.alfresco.web.ui.repo.component.UISimpleSearch + + + + org.alfresco.faces.AdvancedSearch + org.alfresco.web.ui.repo.component.UISearchCustomProperties + + + + org.alfresco.faces.Shelf + org.alfresco.web.ui.repo.component.shelf.UIShelf + + + + org.alfresco.faces.ShelfGroup + org.alfresco.web.ui.repo.component.shelf.UIShelfGroup + + + + org.alfresco.faces.ShelfItem + org.alfresco.web.ui.repo.component.shelf.UIShelfItem + + + + org.alfresco.faces.ClipboardShelfItem + org.alfresco.web.ui.repo.component.shelf.UIClipboardShelfItem + + + + org.alfresco.faces.RecentSpacesShelfItem + org.alfresco.web.ui.repo.component.shelf.UIRecentSpacesShelfItem + + + + org.alfresco.faces.ShortcutsShelfItem + org.alfresco.web.ui.repo.component.shelf.UIShortcutsShelfItem + + + + org.alfresco.faces.LockIcon + org.alfresco.web.ui.repo.component.UILockIcon + + + + org.alfresco.faces.Template + org.alfresco.web.ui.repo.component.template.UITemplate + + + + org.alfresco.faces.MultiValueEditor + org.alfresco.web.ui.repo.component.UIMultiValueEditor + + + + org.alfresco.faces.Actions + org.alfresco.web.ui.repo.component.UIActions + + + + org.alfresco.faces.ActionInstanceEvaluator + org.alfresco.web.ui.repo.component.evaluator.ActionInstanceEvaluator + + + + org.alfresco.faces.NodeInfo + org.alfresco.web.ui.repo.component.UINodeInfo + + + + org.alfresco.faces.DialogButtons + org.alfresco.web.ui.repo.component.UIDialogButtons + + + + org.alfresco.faces.UserGroupPicker + org.alfresco.web.ui.repo.component.UIUserGroupPicker + + + + org.alfresco.faces.WorkflowSummary + org.alfresco.web.ui.repo.component.UIWorkflowSummary + + + + org.alfresco.faces.NodeWorkflowInfo + org.alfresco.web.ui.repo.component.UINodeWorkflowInfo + + + + + org.alfresco.faces.PermissionEvaluator + org.alfresco.web.ui.repo.component.evaluator.PermissionEvaluator + + + + org.alfresco.faces.MimeTypeConverter + org.alfresco.web.ui.repo.converter.MimeTypeConverter + + + + org.alfresco.faces.DisplayPathConverter + org.alfresco.web.ui.repo.converter.DisplayPathConverter + + + + + + + org.alfresco.faces.NodeDescendants + org.alfresco.faces.NodeDescendantsLinkRenderer + org.alfresco.web.ui.repo.renderer.NodeDescendantsLinkRenderer + + + + org.alfresco.faces.NodePath + org.alfresco.faces.NodePathLinkRenderer + org.alfresco.web.ui.repo.renderer.NodePathLinkRenderer + + + + org.alfresco.faces.Property + org.alfresco.faces.PropertyRenderer + org.alfresco.web.ui.repo.renderer.property.PropertyRenderer + + + + org.alfresco.faces.Separator + org.alfresco.faces.SeparatorRenderer + org.alfresco.web.ui.repo.renderer.property.SeparatorRenderer + + + + org.alfresco.faces.Association + org.alfresco.faces.AssociationRenderer + org.alfresco.web.ui.repo.renderer.property.AssociationRenderer + + + + org.alfresco.faces.ChildAssociation + org.alfresco.faces.ChildAssociationRenderer + org.alfresco.web.ui.repo.renderer.property.ChildAssociationRenderer + + + + org.alfresco.faces.MultiValueEditor + org.alfresco.faces.Selector + org.alfresco.web.ui.repo.renderer.MultiValueSelectorRenderer + + + + org.alfresco.faces.MultiValueEditor + org.alfresco.faces.Field + org.alfresco.web.ui.repo.renderer.MultiValueFieldRenderer + + + + +>>>>>>> .merge-right.r4305 diff --git a/source/web/WEB-INF/repo.tld b/source/web/WEB-INF/repo.tld index 5455de2c2f..101e1f9a36 100644 --- a/source/web/WEB-INF/repo.tld +++ b/source/web/WEB-INF/repo.tld @@ -1,1758 +1,1758 @@ - - - - - - 1.0 - 1.2 - r - Alfresco Repository JSF Components - Tag library consisting of Alfresco repository JSF components i.e. those that can only be used in Alfresco based projects - - - propertySheetGrid - org.alfresco.web.ui.repo.tag.property.PropertySheetGridTag - JSP - Property Sheet - Displays the current properties for a node in the repository - - - id - false - true - The component identifier for this component - - - - value - true - true - A NodeRef object representing the node to show the properties of - - - - binding - false - true - The value binding expression linking this component to a property in a backing bean - - - - rendered - false - true - - - - readOnly - false - true - - - - validationEnabled - false - true - - - - finishButtonId - false - true - - - - nextButtonId - false - true - - - - var - false - true - - - - columns - false - true - - - - mode - false - true - Whether the property sheet is in read-only mode or edit mode, values can be "view" or "edit" - - - - labelStyleClass - false - true - - - - cellpadding - false - true - - - - cellspacing - false - true - - - - externalConfig - false - true - - - - configArea - false - true - - - - - property - org.alfresco.web.ui.repo.tag.property.PropertyTag - JSP - - - id - false - true - - - - name - true - true - - - - rendered - false - true - - - - displayLabel - false - true - - - - readOnly - false - true - - - - mode - false - true - - - - converter - false - true - - - - - association - org.alfresco.web.ui.repo.tag.property.AssociationTag - JSP - - - id - false - true - - - - name - true - true - - - - rendered - false - true - - - - displayLabel - false - true - - - - readOnly - false - true - - - - mode - false - true - - - - converter - false - true - - - - - associationEditor - org.alfresco.web.ui.repo.tag.property.AssociationEditorTag - JSP - - - value - true - true - - - - associationName - true - true - - - - availableOptionsSize - false - true - - - - selectItemMsg - false - true - - - - selectItemsMsg - false - true - - - - selectedItemsMsg - false - true - - - - noSelectedItemsMsg - false - true - - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - - childAssociation - org.alfresco.web.ui.repo.tag.property.ChildAssociationTag - JSP - - - id - false - true - - - - name - true - true - - - - rendered - false - true - - - - displayLabel - false - true - - - - readOnly - false - true - - - - mode - false - true - - - - converter - false - true - - - - - childAssociationEditor - org.alfresco.web.ui.repo.tag.property.ChildAssociationEditorTag - JSP - - - value - true - true - - - - associationName - true - true - - - - availableOptionsSize - false - true - - - - selectItemMsg - false - true - - - - selectItemsMsg - false - true - - - - selectedItemsMsg - false - true - - - - noSelectedItemsMsg - false - true - - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - - nodeDescendants - org.alfresco.web.ui.repo.tag.NodeDescendantsTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - maxChildren - false - true - - - - separator - false - true - - - - showEllipses - false - true - - - - action - false - true - - - - actionListener - false - true - - - - value - true - true - - - - - nodePath - org.alfresco.web.ui.repo.tag.NodePathTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - disabled - false - true - - - - showLeaf - false - true - - - - action - false - true - - - - actionListener - false - true - - - - breadcrumb - false - true - - - - value - true - true - - - - - simpleSearch - org.alfresco.web.ui.repo.tag.SimpleSearchTag - JSP - - - Displays controls and icons as the simple search controls needed for the repo client UI. - - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - action - false - true - - - - actionListener - false - true - - - - - systemError - org.alfresco.web.ui.repo.tag.SystemErrorTag - JSP - - - styleClass - false - true - - - - detailsStyleClass - false - true - - - - showDetails - false - true - - - - - page - org.alfresco.web.ui.repo.tag.PageTag - JSP - - - title - false - true - - - - titleId - false - true - - - - - uploadForm - org.alfresco.web.ui.repo.tag.UploadFormTag - JSP - - - - spaceSelector - org.alfresco.web.ui.repo.tag.SpaceSelectorTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - nodeStyle - false - true - - - - nodeStyleClass - false - true - - - - value - false - true - - - - label - true - true - - - - spacing - false - true - - - - initialSelection - false - true - - - - disabled - false - true - - - - - contentSelector - org.alfresco.web.ui.repo.tag.ContentSelectorTag - JSP - - - value - true - true - - - - availableOptionsSize - false - true - - - - multiSelect - false - true - - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - - categorySelector - org.alfresco.web.ui.repo.tag.CategorySelectorTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - nodeStyle - false - true - - - - nodeStyleClass - false - true - - - - value - false - true - - - - label - true - true - - - - spacing - false - true - - - - initialSelection - false - true - - - - disabled - false - true - - - - - mimeTypeSelector - org.alfresco.web.ui.repo.tag.MimeTypeSelectorTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - value - false - true - - - - disabled - false - true - - - - - shelf - org.alfresco.web.ui.repo.tag.shelf.ShelfTag - JSP - - - id - true - true - - - - binding - false - true - - - - rendered - false - true - - - - groupPanel - false - true - - - - groupBgcolor - false - true - - - - selectedGroupPanel - false - true - - - - selectedGroupBgcolor - false - true - - - - innerGroupPanel - false - true - - - - innerGroupBgcolor - false - true - - - - groupExpandedActionListener - false - true - - - - - shelfGroup - org.alfresco.web.ui.repo.tag.shelf.ShelfGroupTag - JSP - - - id - true - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - label - true - true - - - - expanded - false - true - - - - - shelfItem - org.alfresco.web.ui.repo.tag.shelf.ShelfItemTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - tooltip - false - true - - - - - clipboardShelfItem - org.alfresco.web.ui.repo.tag.shelf.ClipboardShelfItemTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - collections - true - true - - - - pasteActionListener - true - true - - - - - recentSpacesShelfItem - org.alfresco.web.ui.repo.tag.shelf.RecentSpacesShelfItemTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - value - true - true - - - - navigateActionListener - true - true - - - - - shortcutsShelfItem - org.alfresco.web.ui.repo.tag.shelf.ShortcutsShelfItemTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - value - true - true - - - - clickActionListener - true - true - - - - removeActionListener - true - true - - - - - lockIcon - org.alfresco.web.ui.repo.tag.LockIconTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - lockImage - false - true - - - - lockOwnerImage - false - true - - - - align - false - true - - - - width - false - true - - - - height - false - true - - - - lockedOwnerTooltip - false - true - - - - lockedUserTooltip - false - true - - - - value - true - true - - - - - template - org.alfresco.web.ui.repo.tag.TemplateTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - engine - false - true - - - - template - true - true - - - - model - false - true - - - - - permissionEvaluator - org.alfresco.web.ui.repo.tag.evaluator.PermissionEvaluatorTag - JSP - - - id - false - true - - - - value - true - true - - - - binding - false - true - - - - allow - false - true - - - - deny - false - true - - - - - multiValueSelector - org.alfresco.web.ui.repo.tag.MultiValueSelectorTag - JSP - - - value - true - true - - - - lastItemAdded - true - true - - - - id - false - true - - - - rendered - false - true - - - - readOnly - false - true - - - - selectItemMsg - false - true - - - - selectedItemsMsg - false - true - - - - noSelectedItemsMsg - false - true - - - - style - false - true - - - - styleClass - false - true - - - - - multiValueField - org.alfresco.web.ui.repo.tag.MultiValueFieldTag - JSP - - - value - true - true - - - - lastItemAdded - true - true - - - - id - false - true - - - - rendered - false - true - - - - readOnly - false - true - - - - selectItemMsg - false - true - - - - selectedItemsMsg - false - true - - - - noSelectedItemsMsg - false - true - - - - style - false - true - - - - styleClass - false - true - - - - - searchCustomProperties - org.alfresco.web.ui.repo.tag.SearchCustomPropertiesTag - JSP - - - id - false - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - bean - true - true - - - - var - true - true - - - - - actions - org.alfresco.web.ui.repo.tag.ActionsTag - JSP - - - The actions component renders a group of actionLink components as defined by an Action Group - in the web-client-config-actions.xml config file. Each action groups can contain many actions - which are individually rendered as ActionLink components. The action group uses a Node object - as the context for the various actions defined in config. - - - - id - false - true - - - - value - true - true - - - - context - true - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - verticalSpacing - false - true - - - - showLink - false - true - - - - - nodeInfo - org.alfresco.web.ui.repo.tag.NodeInfoTag - JSP - - - The nodeInfo component wraps another component, typically an - action link, to provide a floating pop up panel containing - information on a particular node. - - - - id - false - true - - - - value - true - true - - - - - nodeWorkflowInfo - org.alfresco.web.ui.repo.tag.NodeWorkflowInfoTag - JSP - - - The nodeWorkflowInfo component displays information about the workflows - a node is currently involved in. - - - - id - false - true - - - - value - true - true - - - - - dialogButtons - org.alfresco.web.ui.repo.tag.DialogButtonsTag - JSP - - - The dialogButtons component displays the buttons for a dialog. - - - - id - false - true - - - - styleClass - false - true - - - - - userGroupPicker - org.alfresco.web.ui.repo.tag.UserGroupPickerTag - JSP - - - The userGroupPicker component renders a multi-select hierarchical list of groups - and users. The groups and be expanded to show the child users and groups for individual - selection and deselection. - - - - id - false - true - - - - value - true - true - - - - binding - false - true - - - - rendered - false - true - - - - actionListener - false - true - - - - style - false - true - - - - styleClass - false - true - - - - - workflowSummary - org.alfresco.web.ui.repo.tag.WorkflowSummaryTag - JSP - - - Shows summary information of a workflow instance. - - - - id - false - true - - - - value - true - true - - - - binding - false - true - - - - rendered - false - true - - - - style - false - true - - - - styleClass - false - true - - - - + + + + + + 1.0 + 1.2 + r + Alfresco Repository JSF Components + Tag library consisting of Alfresco repository JSF components i.e. those that can only be used in Alfresco based projects + + + propertySheetGrid + org.alfresco.web.ui.repo.tag.property.PropertySheetGridTag + JSP + Property Sheet + Displays the current properties for a node in the repository + + + id + false + true + The component identifier for this component + + + + value + true + true + A NodeRef object representing the node to show the properties of + + + + binding + false + true + The value binding expression linking this component to a property in a backing bean + + + + rendered + false + true + + + + readOnly + false + true + + + + validationEnabled + false + true + + + + finishButtonId + false + true + + + + nextButtonId + false + true + + + + var + false + true + + + + columns + false + true + + + + mode + false + true + Whether the property sheet is in read-only mode or edit mode, values can be "view" or "edit" + + + + labelStyleClass + false + true + + + + cellpadding + false + true + + + + cellspacing + false + true + + + + externalConfig + false + true + + + + configArea + false + true + + + + + property + org.alfresco.web.ui.repo.tag.property.PropertyTag + JSP + + + id + false + true + + + + name + true + true + + + + rendered + false + true + + + + displayLabel + false + true + + + + readOnly + false + true + + + + mode + false + true + + + + converter + false + true + + + + + association + org.alfresco.web.ui.repo.tag.property.AssociationTag + JSP + + + id + false + true + + + + name + true + true + + + + rendered + false + true + + + + displayLabel + false + true + + + + readOnly + false + true + + + + mode + false + true + + + + converter + false + true + + + + + associationEditor + org.alfresco.web.ui.repo.tag.property.AssociationEditorTag + JSP + + + value + true + true + + + + associationName + true + true + + + + availableOptionsSize + false + true + + + + selectItemMsg + false + true + + + + selectItemsMsg + false + true + + + + selectedItemsMsg + false + true + + + + noSelectedItemsMsg + false + true + + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + + childAssociation + org.alfresco.web.ui.repo.tag.property.ChildAssociationTag + JSP + + + id + false + true + + + + name + true + true + + + + rendered + false + true + + + + displayLabel + false + true + + + + readOnly + false + true + + + + mode + false + true + + + + converter + false + true + + + + + childAssociationEditor + org.alfresco.web.ui.repo.tag.property.ChildAssociationEditorTag + JSP + + + value + true + true + + + + associationName + true + true + + + + availableOptionsSize + false + true + + + + selectItemMsg + false + true + + + + selectItemsMsg + false + true + + + + selectedItemsMsg + false + true + + + + noSelectedItemsMsg + false + true + + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + + nodeDescendants + org.alfresco.web.ui.repo.tag.NodeDescendantsTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + maxChildren + false + true + + + + separator + false + true + + + + showEllipses + false + true + + + + action + false + true + + + + actionListener + false + true + + + + value + true + true + + + + + nodePath + org.alfresco.web.ui.repo.tag.NodePathTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + disabled + false + true + + + + showLeaf + false + true + + + + action + false + true + + + + actionListener + false + true + + + + breadcrumb + false + true + + + + value + true + true + + + + + simpleSearch + org.alfresco.web.ui.repo.tag.SimpleSearchTag + JSP + + + Displays controls and icons as the simple search controls needed for the repo client UI. + + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + action + false + true + + + + actionListener + false + true + + + + + systemError + org.alfresco.web.ui.repo.tag.SystemErrorTag + JSP + + + styleClass + false + true + + + + detailsStyleClass + false + true + + + + showDetails + false + true + + + + + page + org.alfresco.web.ui.repo.tag.PageTag + JSP + + + title + false + true + + + + titleId + false + true + + + + + uploadForm + org.alfresco.web.ui.repo.tag.UploadFormTag + JSP + + + + spaceSelector + org.alfresco.web.ui.repo.tag.SpaceSelectorTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + nodeStyle + false + true + + + + nodeStyleClass + false + true + + + + value + false + true + + + + label + true + true + + + + spacing + false + true + + + + initialSelection + false + true + + + + disabled + false + true + + + + + contentSelector + org.alfresco.web.ui.repo.tag.ContentSelectorTag + JSP + + + value + true + true + + + + availableOptionsSize + false + true + + + + multiSelect + false + true + + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + + categorySelector + org.alfresco.web.ui.repo.tag.CategorySelectorTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + nodeStyle + false + true + + + + nodeStyleClass + false + true + + + + value + false + true + + + + label + true + true + + + + spacing + false + true + + + + initialSelection + false + true + + + + disabled + false + true + + + + + mimeTypeSelector + org.alfresco.web.ui.repo.tag.MimeTypeSelectorTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + value + false + true + + + + disabled + false + true + + + + + shelf + org.alfresco.web.ui.repo.tag.shelf.ShelfTag + JSP + + + id + true + true + + + + binding + false + true + + + + rendered + false + true + + + + groupPanel + false + true + + + + groupBgcolor + false + true + + + + selectedGroupPanel + false + true + + + + selectedGroupBgcolor + false + true + + + + innerGroupPanel + false + true + + + + innerGroupBgcolor + false + true + + + + groupExpandedActionListener + false + true + + + + + shelfGroup + org.alfresco.web.ui.repo.tag.shelf.ShelfGroupTag + JSP + + + id + true + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + label + true + true + + + + expanded + false + true + + + + + shelfItem + org.alfresco.web.ui.repo.tag.shelf.ShelfItemTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + tooltip + false + true + + + + + clipboardShelfItem + org.alfresco.web.ui.repo.tag.shelf.ClipboardShelfItemTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + collections + true + true + + + + pasteActionListener + true + true + + + + + recentSpacesShelfItem + org.alfresco.web.ui.repo.tag.shelf.RecentSpacesShelfItemTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + value + true + true + + + + navigateActionListener + true + true + + + + + shortcutsShelfItem + org.alfresco.web.ui.repo.tag.shelf.ShortcutsShelfItemTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + value + true + true + + + + clickActionListener + true + true + + + + removeActionListener + true + true + + + + + lockIcon + org.alfresco.web.ui.repo.tag.LockIconTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + lockImage + false + true + + + + lockOwnerImage + false + true + + + + align + false + true + + + + width + false + true + + + + height + false + true + + + + lockedOwnerTooltip + false + true + + + + lockedUserTooltip + false + true + + + + value + true + true + + + + + template + org.alfresco.web.ui.repo.tag.TemplateTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + engine + false + true + + + + template + true + true + + + + model + false + true + + + + + permissionEvaluator + org.alfresco.web.ui.repo.tag.evaluator.PermissionEvaluatorTag + JSP + + + id + false + true + + + + value + true + true + + + + binding + false + true + + + + allow + false + true + + + + deny + false + true + + + + + multiValueSelector + org.alfresco.web.ui.repo.tag.MultiValueSelectorTag + JSP + + + value + true + true + + + + lastItemAdded + true + true + + + + id + false + true + + + + rendered + false + true + + + + readOnly + false + true + + + + selectItemMsg + false + true + + + + selectedItemsMsg + false + true + + + + noSelectedItemsMsg + false + true + + + + style + false + true + + + + styleClass + false + true + + + + + multiValueField + org.alfresco.web.ui.repo.tag.MultiValueFieldTag + JSP + + + value + true + true + + + + lastItemAdded + true + true + + + + id + false + true + + + + rendered + false + true + + + + readOnly + false + true + + + + selectItemMsg + false + true + + + + selectedItemsMsg + false + true + + + + noSelectedItemsMsg + false + true + + + + style + false + true + + + + styleClass + false + true + + + + + searchCustomProperties + org.alfresco.web.ui.repo.tag.SearchCustomPropertiesTag + JSP + + + id + false + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + bean + true + true + + + + var + true + true + + + + + actions + org.alfresco.web.ui.repo.tag.ActionsTag + JSP + + + The actions component renders a group of actionLink components as defined by an Action Group + in the web-client-config-actions.xml config file. Each action groups can contain many actions + which are individually rendered as ActionLink components. The action group uses a Node object + as the context for the various actions defined in config. + + + + id + false + true + + + + value + true + true + + + + context + true + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + verticalSpacing + false + true + + + + showLink + false + true + + + + + nodeInfo + org.alfresco.web.ui.repo.tag.NodeInfoTag + JSP + + + The nodeInfo component wraps another component, typically an + action link, to provide a floating pop up panel containing + information on a particular node. + + + + id + false + true + + + + value + true + true + + + + + nodeWorkflowInfo + org.alfresco.web.ui.repo.tag.NodeWorkflowInfoTag + JSP + + + The nodeWorkflowInfo component displays information about the workflows + a node is currently involved in. + + + + id + false + true + + + + value + true + true + + + + + dialogButtons + org.alfresco.web.ui.repo.tag.DialogButtonsTag + JSP + + + The dialogButtons component displays the buttons for a dialog. + + + + id + false + true + + + + styleClass + false + true + + + + + userGroupPicker + org.alfresco.web.ui.repo.tag.UserGroupPickerTag + JSP + + + The userGroupPicker component renders a multi-select hierarchical list of groups + and users. The groups and be expanded to show the child users and groups for individual + selection and deselection. + + + + id + false + true + + + + value + true + true + + + + binding + false + true + + + + rendered + false + true + + + + actionListener + false + true + + + + style + false + true + + + + styleClass + false + true + + + + + workflowSummary + org.alfresco.web.ui.repo.tag.WorkflowSummaryTag + JSP + + + Shows summary information of a workflow instance. + + + + id + false + true + + + + value + true + true + + + + binding + false + true + + + + rendered + false + true + + + + style + false + true + + + + styleClass + false + true + + + + diff --git a/source/web/WEB-INF/web.xml b/source/web/WEB-INF/web.xml index 17f6ca3b75..7d857b89c4 100644 --- a/source/web/WEB-INF/web.xml +++ b/source/web/WEB-INF/web.xml @@ -201,6 +201,11 @@ org.alfresco.web.app.servlet.GuestDownloadContentServlet + + guestTemplateContent + org.alfresco.web.app.servlet.GuestTemplateContentServlet + + externalAccess org.alfresco.web.app.servlet.ExternalAccessServlet @@ -266,6 +271,11 @@ /guestDownload/* + + guestTemplateContent + /guestTemplate/* + + externalAccess /navigate/* diff --git a/source/web/css/main.css b/source/web/css/main.css index ca47a41ab1..07afece7a9 100644 --- a/source/web/css/main.css +++ b/source/web/css/main.css @@ -559,25 +559,3 @@ a.topToolbarLinkHighlight, a.topToolbarLinkHighlight:link, a.topToolbarLinkHighl { padding-bottom: 8px; } - -.selectListTable -{ - border: 1px solid #999999; - padding-top: 2px; - padding-left: 2px; - padding-right: 2px; -} - -.selectListItem -{ - background-color: #eeeeee; - border-bottom: 2px solid #ffffff; -} - -.modifiedItemsList -{ - background-color: #EEEEEE; - border-width: 1px; - border-style: dashed; - border-color: #AAAAAA; -} diff --git a/source/web/index.jsp b/source/web/index.jsp index 699051315b..a9b2e386ec 100644 --- a/source/web/index.jsp +++ b/source/web/index.jsp @@ -16,6 +16,7 @@ License. --%> <%@ page import="org.springframework.web.context.support.WebApplicationContextUtils" %> +<%@ page import="org.alfresco.service.cmr.security.PermissionService" %> <%@ page import="org.alfresco.config.ConfigService" %> <%@ page import="org.alfresco.web.app.servlet.AuthenticationHelper" %> <%@ page import="org.alfresco.web.bean.NavigationBean" %> @@ -32,7 +33,7 @@ String location = configElement.getInitialLocation(); // override with the users preference if they have one User user = (User)session.getAttribute(AuthenticationHelper.AUTHENTICATION_USER); -if (user != null) +if (user != null && (user.getUserName().equals(PermissionService.GUEST_AUTHORITY) == false)) { String preference = (String)PreferencesService.getPreferences(user).getValue("start-location"); if (preference != null) diff --git a/source/web/jsp/admin/admin-console.jsp b/source/web/jsp/admin/admin-console.jsp index ae88d603fc..1afb36f029 100644 --- a/source/web/jsp/admin/admin-console.jsp +++ b/source/web/jsp/admin/admin-console.jsp @@ -126,12 +126,6 @@ - - - - - - <% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "ballongrey"); %> diff --git a/source/web/jsp/admin/workflow-console.jsp b/source/web/jsp/admin/workflow-console.jsp new file mode 100644 index 0000000000..37b4e9e181 --- /dev/null +++ b/source/web/jsp/admin/workflow-console.jsp @@ -0,0 +1,102 @@ +<%-- + 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="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> + +<%@ page buffer="32kb" 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 --%> + + + + + + + + + + +
+ + + + + +
+ +
+ +
+ + + + + + + + + + +
User:
Workflow Definition:
+ +
+ + + + + + + + + +
+ + + +
+
+ + + + + + + + +
+
+
+ ----- +
+
+
+ +
+ +
+ + diff --git a/source/web/jsp/roles/manage-content-users.jsp b/source/web/jsp/roles/manage-content-users.jsp index 4d59c638bc..701d910702 100644 --- a/source/web/jsp/roles/manage-content-users.jsp +++ b/source/web/jsp/roles/manage-content-users.jsp @@ -85,13 +85,14 @@ + <%-- View mode settings - <%-- View mode settings --%> + --%> diff --git a/source/web/jsp/roles/manage-invited-users.jsp b/source/web/jsp/roles/manage-invited-users.jsp index 2010add406..73d0306f24 100644 --- a/source/web/jsp/roles/manage-invited-users.jsp +++ b/source/web/jsp/roles/manage-invited-users.jsp @@ -85,13 +85,14 @@ + <%-- View mode settings - <%-- View mode settings --%> + --%> diff --git a/source/web/jsp/workflow/tasks-completed-dashlet.jsp b/source/web/jsp/workflow/tasks-completed-dashlet.jsp index 87b422232c..49245d5c8e 100644 --- a/source/web/jsp/workflow/tasks-completed-dashlet.jsp +++ b/source/web/jsp/workflow/tasks-completed-dashlet.jsp @@ -43,52 +43,41 @@ - - <%-- Source column --%> - - - - - - - - <%-- Created Date column --%> - + - + - + <%-- Completed date column --%> - + - + - + <%-- Outcome column --%> - + - + - + <%-- Actions column --%> - + - + - diff --git a/source/web/jsp/workflow/tasks-todo-dashlet.jsp b/source/web/jsp/workflow/tasks-todo-dashlet.jsp index be2f84d44c..a225ec347e 100644 --- a/source/web/jsp/workflow/tasks-todo-dashlet.jsp +++ b/source/web/jsp/workflow/tasks-todo-dashlet.jsp @@ -44,59 +44,48 @@ - <%-- Source column --%> + <%-- Created Date column --%> - + - - - - - - <%-- Created Date column --%> - - - - - + <%-- Due date column --%> - + - + - + <%-- Status column --%> - + - + - + <%-- Priority column --%> - + - + - + <%-- Actions column --%> - + - + -