diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties
index 4945dd8b9a..fa92b5fa81 100644
--- a/config/alfresco/messages/webclient.properties
+++ b/config/alfresco/messages/webclient.properties
@@ -514,8 +514,7 @@ modify_props_of=Modify Properties of
modify_space_properties=Modify Space Properties
modify_content_properties=Modify Content Properties
preview=Preview in Template
-dashboard_view=Dashboard View
-dashboard=Dashboard
+custom_view=Custom View
view_links=Links
not_inline_editable=This document is not inline editable.
allow_inline_editing=Allow Inline Editing
@@ -546,9 +545,9 @@ success_unlock=Successfully unlocked the document.
inherit_permissions=Inherit Parent Space Permissions
success_inherit_permissions=Successfully changed Inherit Parent Permissions to 'Yes'
success_not_inherit_permissions=Successfully changed Inherit Parent Permissions to 'No'
-apply_dashboard=Apply Dashboard
-apply_dashboard_info=Select a template to be applied to the Space as a Dashboard view.
-apply_dashboard_doc_info=Select a template to be applied to the Document as a Dashboard view.
+apply_template=Apply Template
+apply_dashboard_info=Select a template to be applied to the Space as a Custom view.
+apply_dashboard_doc_info=Select a template to be applied to the Document as a Custom view.
apply_rss_feed=Apply RSS Feed Template
apply_rss_feed_info=Select a template to be applied to the Space as an RSS feed.
apply_rss_feed_warning1=This Space must be visible to the Guest user for the RSS feed to be publically viewable, you can Invite the Guest user using the
@@ -925,6 +924,10 @@ delete_op_files=Only the files within this space.
delete_op_folders=Only the folders within this space.
delete_op_contents=Files and folders within this space.
+# Email users dialog
+email_space_users=Email Space users
+email_space_users_desc=Send an email to the users and groups assigned to this space.
+
# Workflow messages
start_workflow=Start Workflow
start_workflow_wizard=Start New Workflow Wizard
diff --git a/config/alfresco/web-client-config-actions.xml b/config/alfresco/web-client-config-actions.xml
index c6a6467ef7..1484cbaa8a 100644
--- a/config/alfresco/web-client-config-actions.xml
+++ b/config/alfresco/web-client-config-actions.xml
@@ -372,6 +372,17 @@
+
+
+ email_space_users
+ /images/icons/email_users.gif
+ dialog:emailSpaceUsers
+ #{BrowseBean.setupSpaceAction}
+
+ #{actionContext.id}
+
+
+
org.alfresco.web.action.evaluator.ShortcutNodeEvaluator
@@ -601,6 +612,7 @@
+
diff --git a/config/alfresco/web-client-config-dialogs.xml b/config/alfresco/web-client-config-dialogs.xml
index 14e25ad8a8..2768dd5126 100644
--- a/config/alfresco/web-client-config-dialogs.xml
+++ b/config/alfresco/web-client-config-dialogs.xml
@@ -80,7 +80,16 @@
+ description-id="create_topic_description" error-message-id="error_create_topic_dialog" />
+
+
+
+
+
+
+
diff --git a/source/java/org/alfresco/web/bean/TemplateMailHelperBean.java b/source/java/org/alfresco/web/bean/TemplateMailHelperBean.java
new file mode 100644
index 0000000000..6bc9834053
--- /dev/null
+++ b/source/java/org/alfresco/web/bean/TemplateMailHelperBean.java
@@ -0,0 +1,268 @@
+/*
+ * 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.text.MessageFormat;
+import java.util.Map;
+
+import javax.faces.context.FacesContext;
+import javax.faces.event.ActionEvent;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.repository.ContentReader;
+import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.TemplateNode;
+import org.alfresco.web.app.Application;
+import org.alfresco.web.bean.repository.Repository;
+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;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.mail.javamail.MimeMessagePreparator;
+
+/**
+ * @author Kevin Roast
+ */
+public class TemplateMailHelperBean
+{
+ private static Log logger = LogFactory.getLog(TemplateMailHelperBean.class);
+
+ /** JavaMailSender bean reference */
+ protected JavaMailSender mailSender;
+
+ /** NodeService bean reference */
+ protected NodeService nodeService;
+
+ /** dialog state */
+ private String subject = null;
+ private String body = null;
+ private String automaticText = null;
+ private String template = null;
+ private String usingTemplate = null;
+ private String finalBody;
+
+ /**
+ * @param mailSender The JavaMailSender to set.
+ */
+ public void setMailSender(JavaMailSender mailSender)
+ {
+ this.mailSender = mailSender;
+ }
+
+ /**
+ * @param nodeService The nodeService to set.
+ */
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ /**
+ * Initialises the bean
+ */
+ public TemplateMailHelperBean()
+ {
+ subject = "";
+ body = "";
+ automaticText = "";
+ template = null;
+ usingTemplate = null;
+ }
+
+ /**
+ * Send an email notification to the specified User authority
+ *
+ * @param person Person node representing the user
+ * @param node Node they are invited too
+ * @param from From text message
+ * @param roleText The role display label for the user invite notification
+ */
+ public void notifyUser(NodeRef person, NodeRef node, final String from, String roleText)
+ {
+ final String to = (String)this.nodeService.getProperty(person, ContentModel.PROP_EMAIL);
+
+ if (to != null && to.length() != 0)
+ {
+ String body = this.body;
+ if (this.usingTemplate != null)
+ {
+ FacesContext fc = FacesContext.getCurrentInstance();
+
+ // use template service to format the email
+ NodeRef templateRef = new NodeRef(Repository.getStoreRef(), this.usingTemplate);
+ ServiceRegistry services = Repository.getServiceRegistry(fc);
+ Map model = DefaultModelHelper.buildDefaultModel(
+ services, Application.getCurrentUser(fc), templateRef);
+ model.put("role", roleText);
+ model.put("space", new TemplateNode(node, Repository.getServiceRegistry(fc), null));
+
+ body = services.getTemplateService().processTemplate("freemarker", templateRef.toString(), model);
+ }
+ this.finalBody = body;
+
+ MimeMessagePreparator mailPreparer = new MimeMessagePreparator()
+ {
+ public void prepare(MimeMessage mimeMessage) throws MessagingException
+ {
+ MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
+ message.setTo(to);
+ message.setSubject(subject);
+ message.setText(finalBody);
+ message.setFrom(from);
+ }
+ };
+
+ if (logger.isDebugEnabled())
+ logger.debug("Sending notification email to: " + to + "\n...with subject:\n" + subject + "\n...with body:\n" + body);
+
+ try
+ {
+ // Send the message
+ this.mailSender.send(mailPreparer);
+ }
+ catch (Throwable e)
+ {
+ // don't stop the action but let admins know email is not getting sent
+ logger.error("Failed to send email to " + to, e);
+ }
+ }
+ }
+
+ /**
+ * Action handler called to insert a template as the email body
+ */
+ public void insertTemplate(ActionEvent event)
+ {
+ if (this.template != null && this.template.equals(TemplateSupportBean.NO_SELECTION) == false)
+ {
+ // get the content of the template so the user can get a basic preview of it
+ try
+ {
+ NodeRef templateRef = new NodeRef(Repository.getStoreRef(), this.template);
+ ContentService cs = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getContentService();
+ ContentReader reader = cs.getReader(templateRef, ContentModel.PROP_CONTENT);
+ if (reader != null && reader.exists())
+ {
+ this.body = reader.getContentString();
+
+ this.usingTemplate = this.template;
+ }
+ }
+ catch (Throwable err)
+ {
+ Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
+ FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
+ }
+ }
+ }
+
+ /**
+ * Action handler called to discard the template from the email body
+ */
+ public void discardTemplate(ActionEvent event)
+ {
+ this.body = this.automaticText;
+ usingTemplate = null;
+ }
+
+ /**
+ * @return Returns the email body text.
+ */
+ public String getBody()
+ {
+ return this.body;
+ }
+
+ /**
+ * @param body The email body text to set.
+ */
+ public void setBody(String body)
+ {
+ this.body = body;
+ }
+
+ /**
+ * @return Returns the email subject text.
+ */
+ public String getSubject()
+ {
+ return this.subject;
+ }
+
+ /**
+ * @param subject The email subject text to set.
+ */
+ public void setSubject(String subject)
+ {
+ this.subject = subject;
+ }
+
+ /**
+ * @return Returns the automatic text.
+ */
+ public String getAutomaticText()
+ {
+ return this.automaticText;
+ }
+
+ /**
+ * @param automaticText The automatic text to set.
+ */
+ public void setAutomaticText(String automaticText)
+ {
+ this.automaticText = automaticText;
+ }
+
+ /**
+ * @return Returns the email template Id
+ */
+ public String getTemplate()
+ {
+ return this.template;
+ }
+
+ /**
+ * @param template The email template to set.
+ */
+ public void setTemplate(String template)
+ {
+ this.template = template;
+ }
+
+ /**
+ * @return Returns if a template has been inserted by a user for email body.
+ */
+ public String getUsingTemplate()
+ {
+ return this.usingTemplate;
+ }
+
+ /**
+ * @param usingTemplate Template that has been inserted by a user for the email body.
+ */
+ public void setUsingTemplate(String usingTemplate)
+ {
+ this.usingTemplate = usingTemplate;
+ }
+}
diff --git a/source/java/org/alfresco/web/bean/users/EmailSpaceUsersDialog.java b/source/java/org/alfresco/web/bean/users/EmailSpaceUsersDialog.java
new file mode 100644
index 0000000000..53eb16465f
--- /dev/null
+++ b/source/java/org/alfresco/web/bean/users/EmailSpaceUsersDialog.java
@@ -0,0 +1,497 @@
+/*
+ * 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.users;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.context.FacesContext;
+import javax.faces.event.ActionEvent;
+import javax.transaction.UserTransaction;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.repository.InvalidNodeRefException;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.security.AccessPermission;
+import org.alfresco.service.cmr.security.AccessStatus;
+import org.alfresco.service.cmr.security.AuthorityService;
+import org.alfresco.service.cmr.security.AuthorityType;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.web.app.Application;
+import org.alfresco.web.app.context.IContextListener;
+import org.alfresco.web.app.context.UIContextService;
+import org.alfresco.web.bean.TemplateMailHelperBean;
+import org.alfresco.web.bean.dialog.BaseDialogBean;
+import org.alfresco.web.bean.repository.MapNode;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+import org.alfresco.web.bean.repository.User;
+import org.alfresco.web.ui.common.Utils;
+import org.alfresco.web.ui.repo.WebResources;
+import org.alfresco.web.ui.repo.component.UIUserGroupPicker;
+import org.alfresco.web.ui.repo.component.UIUserGroupPicker.PickerEvent;
+import org.springframework.mail.javamail.JavaMailSender;
+
+/**
+ * Dialog bean managing the state for the Email Space Users page. Calculates the user/groups
+ * that are invited to a space and builds the data structures needed to display and modify
+ * the list in the web-client UI. Notifies the selected user/groups with a templatable email.
+ *
+ * @author Kevin Roast
+ */
+public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextListener
+{
+ private static final String PROP_DUPLICATE = "duplicate";
+ private static final String PROP_PARENT = "parent";
+ private static final String PROP_ID = "id";
+ private static final String PROP_ISGROUP = "isGroup";
+ private static final String PROP_ICON = "icon";
+ private static final String PROP_FULLNAME = "fullName";
+ private static final String PROP_ROLES = "roles";
+ private static final String PROP_EXPANDED = "expanded";
+ private static final String PROP_SELECTED = "selected";
+ private static final String PROP_USERNAME = "userName";
+
+ /** Injected Bean references */
+ protected PermissionService permissionService;
+ protected PersonService personService;
+ protected AuthorityService authorityService;
+ protected JavaMailSender mailSender;
+
+ /** Helper providing template based mailing facilities */
+ protected TemplateMailHelperBean mailHelper;
+
+ /** List of user/group property map/node instances */
+ private List