diff --git a/config/alfresco/quickshare/quickshare-clients.properties b/config/alfresco/quickshare/quickshare-clients.properties
new file mode 100644
index 0000000000..9187b8072f
--- /dev/null
+++ b/config/alfresco/quickshare/quickshare-clients.properties
@@ -0,0 +1,4 @@
+# registry of clients that are able to email shared links
+
+quickshare.client.sfs.sharedLinkBaseUrl=http://localhost:8082/sfs/s
+quickshare.client.sfs.templateAssetsUrl=http://localhost:8082/sfs
diff --git a/config/alfresco/templates/quickshare-email-templates/quickshare-email.default.template.ftl b/config/alfresco/templates/quickshare-email-templates/quickshare-email.default.template.ftl
index 55ac0e2a02..1bf90e535d 100644
--- a/config/alfresco/templates/quickshare-email-templates/quickshare-email.default.template.ftl
+++ b/config/alfresco/templates/quickshare-email-templates/quickshare-email.default.template.ftl
@@ -261,7 +261,7 @@
"http://go.alfresco.com/a0100K050L0000KZjI2d00U" target="_blank"
>
@@ -298,7 +298,7 @@
|
@@ -394,23 +394,23 @@ middle;">${shared_node_name} shared with you
  |
+ src="${template_assets_url}/Alfresco_Icon_Social_Google.png" width="23" height="23" border="0">
|

+ src="${template_assets_url}/AlfrrescoGlobal_Logo_BW.png" border="0" alt="alfresco.com" width="92" height="29">
|
diff --git a/source/java/org/alfresco/repo/quickshare/ClientAppConfig.java b/source/java/org/alfresco/repo/quickshare/ClientAppConfig.java
new file mode 100644
index 0000000000..de7346d765
--- /dev/null
+++ b/source/java/org/alfresco/repo/quickshare/ClientAppConfig.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2005-2016 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.quickshare;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.extensions.surf.util.AbstractLifecycleBean;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * This class picks up all the loaded properties passed to it and uses a naming
+ * convention to isolate the client's name and related values.
+ * So, if a new client (e.g. MyClientName) is required to send shared-link email, then the following
+ * needs to be put into a properties file.
+ *
+ * - quickshare.client.MyClientName.sharedLinkBaseUrl=http://localhost:8080/MyClientName/s
+ * - quickshare.client.MyClientName.templateAssetsUrl=http://localhost:8080/MyClientName/assets
+ *
+ * The default property file is alfresco/quickshare/quickshare-clients.properties which
+ * could be overridden by alfresco-global properties file.
+ *
+ * @author Jamal Kaabi-Mofrad
+ */
+public class ClientAppConfig extends AbstractLifecycleBean
+{
+ private static final Log logger = LogFactory.getLog(ClientAppConfig.class);
+
+ public static final String PREFIX = "quickshare.client.";
+ public static final String PROP_SHARED_LINK_BASE_URL = "sharedLinkBaseUrl";
+ public static final String PROP_TEMPLATE_ASSETS_URL = "templateAssetsUrl";
+
+ private Properties defaultProperties;
+ private Properties globalProperties;
+
+ private ConcurrentMap clients = new ConcurrentHashMap<>();
+
+ public ClientAppConfig()
+ {
+ }
+
+ public void setDefaultProperties(Properties defaultProperties)
+ {
+ this.defaultProperties = defaultProperties;
+ }
+
+ public void setGlobalProperties(Properties globalProperties)
+ {
+ this.globalProperties = globalProperties;
+ }
+
+ @Override
+ protected void onBootstrap(ApplicationEvent event)
+ {
+ load();
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("All bootstrapped quickShare clients: " + clients);
+ }
+ }
+
+ @Override
+ protected void onShutdown(ApplicationEvent event)
+ {
+ // nothing to do
+ }
+
+ public void load()
+ {
+ Map mergedProperties = getAndMergeProperties();
+ Set clientsNames = processPropertyKeys(mergedProperties);
+ clients.putAll(processClients(clientsNames, mergedProperties));
+ }
+
+ public Map getClients()
+ {
+ return Collections.unmodifiableMap(clients);
+ }
+
+ public ClientApp getClient(String name)
+ {
+ return clients.get(name);
+ }
+
+ public void setClient(ClientApp client)
+ {
+ if (client != null)
+ {
+ clients.put(client.getName(), client);
+ }
+ }
+
+ public boolean removeClient(String name)
+ {
+ ClientApp client = clients.remove(name);
+ return (client != null);
+ }
+
+ protected Set processPropertyKeys(Map allProps)
+ {
+ Set clientsNames = new HashSet<>();
+ for (String key : allProps.keySet())
+ {
+ String propKey = key;
+ if (propKey.startsWith(PREFIX))
+ {
+ propKey = propKey.substring(PREFIX.length());
+ // Find the client name
+ int clientNameControlDot = propKey.indexOf('.');
+ if (clientNameControlDot < 1)
+ {
+ logMalformedPropertyKey(key);
+ continue;
+ }
+
+ int propNameLength = (propKey.length() - clientNameControlDot) - 1; // Length of characters between dots
+ if (propNameLength < 1)
+ {
+ logMalformedPropertyKey(key);
+ continue;
+ }
+ String clientName = propKey.substring(0, clientNameControlDot);
+ String propName = propKey.substring((clientNameControlDot + 1));
+ if (PROP_SHARED_LINK_BASE_URL.equals(propName) || PROP_TEMPLATE_ASSETS_URL.equals(propName))
+ {
+ clientsNames.add(clientName);
+ }
+ else
+ {
+ logMalformedPropertyKey(key);
+ }
+ }
+ else
+ {
+ logMalformedPropertyKey(propKey);
+ }
+ }
+ return clientsNames;
+ }
+
+ protected Map processClients(Set clientsNames, Map allProps)
+ {
+ Map clientApps = new HashMap<>(clientsNames.size());
+ for (String name : clientsNames)
+ {
+ String propKey = getPropertyKey(name, PROP_SHARED_LINK_BASE_URL);
+ String sharedLinkBaseUrl = allProps.get(propKey);
+ if (StringUtils.isEmpty(sharedLinkBaseUrl))
+ {
+ logInvalidPropertyValue(propKey, sharedLinkBaseUrl);
+ continue;
+ }
+
+ propKey = getPropertyKey(name, PROP_TEMPLATE_ASSETS_URL);
+ String templateAssetsUrl = allProps.get(propKey);
+ if (StringUtils.isEmpty(templateAssetsUrl))
+ {
+ logInvalidPropertyValue(propKey, templateAssetsUrl);
+ continue;
+ }
+ // Create the client data
+ ClientApp client = new ClientApp(name, sharedLinkBaseUrl, templateAssetsUrl);
+ clientApps.put(name, client);
+ }
+ return clientApps;
+ }
+
+ protected Map getAndMergeProperties()
+ {
+ Map allProperties = new HashMap<>();
+ for (String propKey : defaultProperties.stringPropertyNames())
+ {
+ allProperties.put(propKey, defaultProperties.getProperty(propKey));
+
+ }
+
+ //override default values from other property files
+ for (String propKey : globalProperties.stringPropertyNames())
+ {
+ if (propKey.startsWith(PREFIX))
+ {
+ allProperties.put(propKey, globalProperties.getProperty(propKey));
+ }
+ }
+
+ return allProperties;
+ }
+
+ private void logMalformedPropertyKey(String propName)
+ {
+ logger.warn("Ignoring quickShare client (malformed property key): " + propName);
+ }
+
+ private void logInvalidPropertyValue(String propName, String propValue)
+ {
+ logger.warn("Ignoring quickShare client (invalid value) [" + propValue + "] for the property:" + propName);
+ }
+
+ private String getPropertyKey(String clientName, String clientProp)
+ {
+ return PREFIX + clientName + '.' + clientProp;
+ }
+
+ public static class ClientApp
+ {
+ private final String name;
+ private final String sharedLinkBaseUrl;
+ private final String templateAssetsUrl;
+
+ public ClientApp(String name, String sharedLinkBaseUrl, String templateAssetsUrl)
+ {
+ this.name = name;
+ this.sharedLinkBaseUrl = sharedLinkBaseUrl;
+ this.templateAssetsUrl = templateAssetsUrl;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getSharedLinkBaseUrl()
+ {
+ return sharedLinkBaseUrl;
+ }
+
+ public String getTemplateAssetsUrl()
+ {
+ return templateAssetsUrl;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (!(o instanceof ClientApp))
+ {
+ return false;
+ }
+
+ ClientApp clientApp = (ClientApp) o;
+ return getName().equals(clientApp.getName());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return getName().hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ final StringBuilder sb = new StringBuilder(250);
+ sb.append("ClientApp [name=").append(name)
+ .append(", sharedLinkBaseUrl=").append(sharedLinkBaseUrl)
+ .append(", templateAssetsUrl=").append(templateAssetsUrl)
+ .append(']');
+ return sb.toString();
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/quickshare/QuickShareClientNotFoundException.java b/source/java/org/alfresco/repo/quickshare/QuickShareClientNotFoundException.java
new file mode 100644
index 0000000000..89168da280
--- /dev/null
+++ b/source/java/org/alfresco/repo/quickshare/QuickShareClientNotFoundException.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005-2016 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.quickshare;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+
+/**
+ * @author Jamal Kaabi-Mofrad
+ */
+public class QuickShareClientNotFoundException extends AlfrescoRuntimeException
+{
+ private static final long serialVersionUID = -2567136374291827783L;
+
+ public QuickShareClientNotFoundException(String msgId)
+ {
+ super(msgId);
+ }
+
+ public QuickShareClientNotFoundException(String msgId, Object[] msgParams)
+ {
+ super(msgId, msgParams);
+ }
+}
diff --git a/source/java/org/alfresco/repo/quickshare/QuickShareServiceImpl.java b/source/java/org/alfresco/repo/quickshare/QuickShareServiceImpl.java
index f9977ae4a0..b88dbb6b4a 100644
--- a/source/java/org/alfresco/repo/quickshare/QuickShareServiceImpl.java
+++ b/source/java/org/alfresco/repo/quickshare/QuickShareServiceImpl.java
@@ -29,7 +29,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.events.types.ActivityEvent;
import org.alfresco.events.types.Event;
import org.alfresco.model.ContentModel;
@@ -47,6 +46,7 @@ import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
+import org.alfresco.repo.quickshare.ClientAppConfig.ClientApp;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.permissions.AccessDeniedException;
@@ -105,7 +105,9 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
private static final String FTL_SENDER_MESSAGE = "sender_message";
private static final String FTL_SENDER_FIRST_NAME = "sender_first_name";
private static final String FTL_SENDER_LAST_NAME = "sender_last_name";
+ private static final String FTL_TEMPLATE_ASSETS_URL = "template_assets_url";
private static final String DEFAULT_EMAIL_SUBJECT = "quickshare.notifier.email.subject";
+ private static final String EMAIL_TEMPLATE_REF ="alfresco/templates/quickshare-email-templates/quickshare-email.default.template.ftl";
private AttributeService attributeService;
private DictionaryService dictionaryService;
@@ -123,7 +125,7 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
private boolean enabled;
private String defaultEmailSender;
- private Map templateRegistry;
+ private ClientAppConfig clientAppConfig;
/**
* Set the attribute service
@@ -240,11 +242,11 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
}
/**
- * Set the templates
+ * Set the quickShare clientAppConfig
*/
- public void setTemplateRegistry(Map templateRegistry)
+ public void setClientAppConfig(ClientAppConfig clientAppConfig)
{
- this.templateRegistry = templateRegistry;
+ this.clientAppConfig = clientAppConfig;
}
private void checkMandatoryProperties()
@@ -262,7 +264,7 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
PropertyCheck.mandatory(this, "preferenceService", preferenceService);
PropertyCheck.mandatory(this, "behaviourFilter", behaviourFilter);
PropertyCheck.mandatory(this, "defaultEmailSender", defaultEmailSender);
- PropertyCheck.mandatory(this, "templateRegistry", templateRegistry);
+ PropertyCheck.mandatory(this, "clientAppConfig", clientAppConfig);
}
/**
@@ -677,9 +679,10 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
ParameterCheck.mandatory("emailRequest", emailRequest);
emailRequest.validate();
- if (!templateRegistry.containsKey(emailRequest.getTemplateId()))
+ ClientApp clientApp = clientAppConfig.getClient(emailRequest.getClient());
+ if (clientApp == null)
{
- throw new AlfrescoRuntimeException("Invalid template. Couldn't find a template with id:" + emailRequest.getTemplateId());
+ throw new QuickShareClientNotFoundException("Client was not found [" + emailRequest.getClient() + "]");
}
// Set the details of the person sending the email
@@ -688,31 +691,30 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
final Map senderProps = nodeService.getProperties(senderNodeRef);
final String senderFirstName = (String) senderProps.get(ContentModel.PROP_FIRSTNAME);
final String senderLastName = (String) senderProps.get(ContentModel.PROP_LASTNAME);
- final String senderEmail = (String) senderProps.get(ContentModel.PROP_EMAIL);
final String senderFullName = ((senderFirstName != null ? senderFirstName + " " : "") + (senderLastName != null ? senderLastName : "")).trim();
// Set the default model information
- Map templateModel = new HashMap<>(5);
+ Map templateModel = new HashMap<>(6);
templateModel.put(FTL_SENDER_FIRST_NAME, senderFirstName);
templateModel.put(FTL_SENDER_LAST_NAME, senderLastName);
- templateModel.put(FTL_SHARED_NODE_URL, emailRequest.getSharedNodeURL());
+ final String sharedNodeUrl = getUrl(clientApp.getSharedLinkBaseUrl()) + '/' + emailRequest.getSharedId();
+ templateModel.put(FTL_SHARED_NODE_URL, sharedNodeUrl);
templateModel.put(FTL_SHARED_NODE_NAME, emailRequest.getSharedNodeName());
templateModel.put(FTL_SENDER_MESSAGE, emailRequest.getSenderMessage());
-
- // Email sender
- // By default the current-user's email address will not be used to send this mail.
- // However, current-user's first and lastname will be used as the personal name.
- final String from = (!emailRequest.isSendFromDefaultEmail() && senderEmail != null) ? senderEmail : this.defaultEmailSender;
+ String templateAssetsUrl = getUrl(clientApp.getTemplateAssetsUrl());
+ templateModel.put(FTL_TEMPLATE_ASSETS_URL, templateAssetsUrl);
// Set the email details
Map actionParams = new HashMap<>();
- actionParams.put(MailActionExecuter.PARAM_FROM, from);
+ // Email sender. By default the current-user's email address will not be used to send this mail.
+ // However, current-user's first and lastname will be used as the personal name.
+ actionParams.put(MailActionExecuter.PARAM_FROM, this.defaultEmailSender);
actionParams.put(MailActionExecuter.PARAM_FROM_PERSONAL_NAME, senderFullName);
actionParams.put(MailActionExecuter.PARAM_SUBJECT, DEFAULT_EMAIL_SUBJECT);
actionParams.put(MailActionExecuter.PARAM_SUBJECT_PARAMS, new Object[] { senderFirstName, senderLastName, emailRequest.getSharedNodeName() });
actionParams.put(MailActionExecuter.PARAM_IGNORE_SEND_FAILURE, emailRequest.isIgnoreSendFailure());
// Pick the template
- actionParams.put(MailActionExecuter.PARAM_TEMPLATE, templateRegistry.get(emailRequest.getTemplateId()));
+ actionParams.put(MailActionExecuter.PARAM_TEMPLATE, EMAIL_TEMPLATE_REF);
actionParams.put(MailActionExecuter.PARAM_TEMPLATE_MODEL, (Serializable) templateModel);
actionParams.put(MailActionExecuter.PARAM_LOCALE, getDefaultIfNull(getEmailCreatorLocale(authenticatedUser), emailRequest.getLocale()));
@@ -725,6 +727,15 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
}
}
+ private String getUrl(String url)
+ {
+ if (url.endsWith("/"))
+ {
+ return url.substring(0, url.length() - 1);
+ }
+ return url;
+ }
+
private T getDefaultIfNull(T defaultValue, T newValue)
{
return (newValue == null) ? defaultValue : newValue;
@@ -742,11 +753,9 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
public static class QuickShareEmailRequest
{
/**
- * Whether to send an email from the default email address or use the current-user's email (if not null).
- * The default is true.
+ * The client's name that must be registered in order to send emails.
*/
- private boolean sendFromDefaultEmail = true;
-
+ private String client;
/**
* Optional Locale for subject and body text
*/
@@ -758,19 +767,15 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
private Set toEmails;
/**
- * The template id. If not provided, a default template will be used.
+ * The shared id.
*/
- private String templateId = "default";
-
- /**
- * The shared content URL.
- */
- private String sharedNodeURL;
+ private String sharedId;
/**
* The shared content name.
*/
private String sharedNodeName;
+
/**
* Optional message from the sender.
*/
@@ -784,29 +789,8 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
public void validate()
{
ParameterCheck.mandatoryCollection("toEmails", toEmails);
- ParameterCheck.mandatoryString("templateId", templateId);
- ParameterCheck.mandatoryString("sharedNodeURL", sharedNodeURL);
+ ParameterCheck.mandatoryString("sharedId", sharedId);
ParameterCheck.mandatoryString("sharedNodeName", sharedNodeName);
- ParameterCheck.mandatoryString("senderMessage", senderMessage);
- }
-
- /**
- * {@link QuickShareEmailRequest#sendFromDefaultEmail}
- */
- public boolean isSendFromDefaultEmail()
- {
- return sendFromDefaultEmail;
- }
-
- /**
- * {@link QuickShareEmailRequest#sendFromDefaultEmail}
- */
- public void setSendFromDefaultEmail(Boolean sendFromDefaultEmail)
- {
- if (sendFromDefaultEmail != null)
- {
- this.sendFromDefaultEmail = sendFromDefaultEmail;
- }
}
/**
@@ -845,38 +829,37 @@ public class QuickShareServiceImpl implements QuickShareService, NodeServicePoli
}
/**
- * {@link QuickShareEmailRequest#templateId}
+ * {@link QuickShareEmailRequest#client}
*/
- public String getTemplateId()
+ public String getClient()
{
- return templateId;
+ return client;
}
/**
- * {@link QuickShareEmailRequest#templateId}
+ * {@link QuickShareEmailRequest#client}
*/
- public void setTemplateId(String templateId)
+ public QuickShareEmailRequest setClient(String client)
{
- if (templateId != null)
- {
- this.templateId = templateId;
- }
+ this.client = client;
+ return this;
}
/**
- * {@link QuickShareEmailRequest#sharedNodeURL}
+ * {@link QuickShareEmailRequest#sharedId}
*/
- public String getSharedNodeURL()
+ public String getSharedId()
{
- return sharedNodeURL;
+ return sharedId;
}
/**
- * {@link QuickShareEmailRequest#sharedNodeURL}
+ * {@link QuickShareEmailRequest#sharedId}
*/
- public void setSharedNodeURL(String sharedNodeURL)
+ public QuickShareEmailRequest setSharedId(String sharedId)
{
- this.sharedNodeURL = sharedNodeURL;
+ this.sharedId = sharedId;
+ return this;
}
/**