NIHVIVO-2693 Add Freemarker user-defined directive for email and integrate into email messaging framework.
This commit is contained in:
parent
9c9f7dfe57
commit
2fcff042e6
9 changed files with 260 additions and 18 deletions
|
@ -200,7 +200,7 @@ public class UserAccountsEditPage extends UserAccountsPage {
|
|||
|
||||
userAccountsDao.updateUserAccount(userAccount);
|
||||
|
||||
strategy.notifyUser();
|
||||
strategy.notifyUser(vreq);
|
||||
}
|
||||
|
||||
public boolean wasPasswordEmailSent() {
|
||||
|
|
|
@ -47,7 +47,7 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
|
|||
|
||||
protected abstract void setAdditionalProperties(UserAccount u);
|
||||
|
||||
protected abstract void notifyUser();
|
||||
protected abstract void notifyUser(VitroRequest vreq);
|
||||
|
||||
protected abstract boolean wasPasswordEmailSent();
|
||||
|
||||
|
@ -57,7 +57,8 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
|
|||
|
||||
private static class EmailStrategy extends UserAccountsEditPageStrategy {
|
||||
private static final String PARAMETER_RESET_PASSWORD = "resetPassword";
|
||||
|
||||
private static final String EMAIL_TEMPLATE = "userAccounts-resetPasswordEmail.ftl";
|
||||
|
||||
public static final String RESET_PASSWORD_URL = "/accounts/resetPassword";
|
||||
|
||||
private boolean resetPassword;
|
||||
|
@ -94,7 +95,7 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void notifyUser() {
|
||||
protected void notifyUser(VitroRequest vreq) {
|
||||
if (!resetPassword) {
|
||||
return;
|
||||
}
|
||||
|
@ -102,16 +103,21 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
|
|||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
body.put("userAccount", page.getUpdatedAccount());
|
||||
body.put("passwordLink", buildResetPasswordLink());
|
||||
body.put("subjectLine", "Reset password request");
|
||||
//body.put("subjectLine", "Reset password request");
|
||||
|
||||
FreemarkerEmailMessage email = FreemarkerEmailFactory
|
||||
.createNewMessage(vreq);
|
||||
email.addRecipient(TO, page.getUpdatedAccount().getEmailAddress());
|
||||
email.setSubject("Reset password request");
|
||||
email.setHtmlTemplate("userAccounts-resetPasswordEmail-html.ftl");
|
||||
email.setTextTemplate("userAccounts-resetPasswordEmail-text.ftl");
|
||||
email.setBodyMap(body);
|
||||
email.send();
|
||||
|
||||
vreq.setAttribute("email", email);
|
||||
|
||||
email.processTemplate(vreq, EMAIL_TEMPLATE, body);
|
||||
|
||||
//email.setSubject("Reset password request");
|
||||
//email.setHtmlTemplate("userAccounts-resetPasswordEmail-html.ftl");
|
||||
//email.setTextTemplate("userAccounts-resetPasswordEmail-text.ftl");
|
||||
//email.setBodyMap(body);
|
||||
//email.send();
|
||||
|
||||
sentEmail = true;
|
||||
}
|
||||
|
@ -193,7 +199,7 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void notifyUser() {
|
||||
protected void notifyUser(VitroRequest vreq) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
|
|
|
@ -306,11 +306,18 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
|
|||
*/
|
||||
public static Map<String, Object> getDirectives() {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("dump", new freemarker.ext.dump.DumpDirective());
|
||||
map.put("dumpAll", new freemarker.ext.dump.DumpAllDirective());
|
||||
map.put("help", new freemarker.ext.dump.HelpDirective());
|
||||
map.putAll(getDirectivesForAllEnvironments());
|
||||
map.put("url", new edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective());
|
||||
map.put("widget", new edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective());
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public static Map<String, Object> getDirectivesForAllEnvironments() {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("dump", new freemarker.ext.dump.DumpDirective());
|
||||
map.put("dumpAll", new freemarker.ext.dump.DumpAllDirective());
|
||||
map.put("help", new freemarker.ext.dump.HelpDirective());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
package edu.cornell.mannlib.vitro.webapp.email;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -27,9 +29,14 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.TemplateProcessingHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.TemplateProcessingHelper.TemplateProcessingException;
|
||||
import freemarker.core.Environment;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
|
||||
/**
|
||||
* A framework that makes it simpler to send email messages with a body built
|
||||
|
@ -146,6 +153,69 @@ public class FreemarkerEmailMessage {
|
|||
.unmodifiableMap(new HashMap<String, Object>(body));
|
||||
}
|
||||
}
|
||||
|
||||
public void processTemplate(VitroRequest vreq, String templateName, Map<String, Object> map) {
|
||||
|
||||
vreq.setAttribute("email", this);
|
||||
|
||||
map.putAll(FreemarkerHttpServlet.getDirectivesForAllEnvironments());
|
||||
map.put("email", new edu.cornell.mannlib.vitro.webapp.web.directives.EmailDirective());
|
||||
|
||||
try {
|
||||
Template template = config.getTemplate(templateName);
|
||||
StringWriter writer = new StringWriter();
|
||||
Environment env = template.createProcessingEnvironment(map, writer);
|
||||
env.setCustomAttribute("request", vreq);
|
||||
env.process();
|
||||
} catch (TemplateException e) {
|
||||
log.error(e, e);
|
||||
} catch (IOException e) {
|
||||
log.error(e, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void send(String subject, String html, String text) {
|
||||
try {
|
||||
MimeMessage msg = new MimeMessage(session);
|
||||
msg.setReplyTo(new Address[] { replyToAddress });
|
||||
|
||||
if (fromAddress == null) {
|
||||
msg.addFrom(new Address[] { replyToAddress });
|
||||
} else {
|
||||
msg.addFrom(new Address[] { fromAddress });
|
||||
}
|
||||
|
||||
for (Recipient recipient : recipients) {
|
||||
msg.addRecipient(recipient.type, recipient.address);
|
||||
}
|
||||
|
||||
msg.setSubject(subject);
|
||||
|
||||
if (html.isEmpty()) {
|
||||
if (html.isEmpty()) {
|
||||
log.error("Message has neither text body nor HTML body");
|
||||
} else {
|
||||
msg.setContent(html, "text/html");
|
||||
}
|
||||
} else {
|
||||
if (html.isEmpty()) {
|
||||
msg.setContent(text, "text/plain");
|
||||
} else {
|
||||
MimeMultipart content = new MimeMultipart("alternative");
|
||||
addBodyPart(content, text, "text/plain");
|
||||
addBodyPart(content, html, "text/html");
|
||||
msg.setContent(content);
|
||||
}
|
||||
}
|
||||
|
||||
msg.setSentDate(new Date());
|
||||
|
||||
Transport.send(msg);
|
||||
|
||||
} catch (MessagingException e) {
|
||||
log.error("Failed to send message.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void send() {
|
||||
String textBody = figureMessageBody(textTemplateName);
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.web.directives;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
|
||||
import freemarker.core.Environment;
|
||||
import freemarker.template.SimpleScalar;
|
||||
import freemarker.template.TemplateDirectiveBody;
|
||||
import freemarker.template.TemplateException;
|
||||
import freemarker.template.TemplateModel;
|
||||
import freemarker.template.TemplateModelException;
|
||||
|
||||
public class EmailDirective extends BaseTemplateDirectiveModel {
|
||||
|
||||
private static final Log log = LogFactory.getLog(EmailDirective.class);
|
||||
|
||||
@Override
|
||||
public void execute(Environment env, Map params, TemplateModel[] loopVars,
|
||||
TemplateDirectiveBody body) throws TemplateException, IOException {
|
||||
|
||||
Object o = params.get("subject");
|
||||
if (o == null) {
|
||||
throw new TemplateModelException(
|
||||
"The email directive requires a value for parameter 'subject'.");
|
||||
}
|
||||
if (! ( o instanceof SimpleScalar)) {
|
||||
throw new TemplateModelException(
|
||||
"The email directive requires a string value for parameter 'subject'.");
|
||||
}
|
||||
String subject = o.toString();
|
||||
|
||||
o = params.get("html");
|
||||
if (o == null) {
|
||||
throw new TemplateModelException(
|
||||
"The email directive requires a value for parameter 'html'.");
|
||||
}
|
||||
if (! ( o instanceof SimpleScalar)) {
|
||||
throw new TemplateModelException(
|
||||
"The email directive requires a string value for parameter 'html'.");
|
||||
}
|
||||
String html = o.toString();
|
||||
|
||||
o = params.get("text");
|
||||
if (o == null) {
|
||||
throw new TemplateModelException(
|
||||
"The email directive requires a value for parameter 'text'.");
|
||||
}
|
||||
if (! ( o instanceof SimpleScalar)) {
|
||||
throw new TemplateModelException(
|
||||
"The email directive requires a string value for parameter 'text'.");
|
||||
}
|
||||
String text = o.toString();
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest) env.getCustomAttribute("request");
|
||||
|
||||
o = (FreemarkerEmailMessage) request.getAttribute("email");
|
||||
if ( o == null) {
|
||||
throw new TemplateModelException(
|
||||
"No email object found in the request.");
|
||||
}
|
||||
if ( ! (o instanceof FreemarkerEmailMessage)) {
|
||||
throw new TemplateModelException(
|
||||
"Invalid value for request email attribute");
|
||||
}
|
||||
FreemarkerEmailMessage email = (FreemarkerEmailMessage) o;
|
||||
email.send(subject, html, text);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> help(String name) {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
|
||||
map.put("effect", "Create an email message from the parameters set in the invoking template.");
|
||||
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("subject", "email subject");
|
||||
params.put("html", "HTML version of email message");
|
||||
params.put("text", "Plain text version of email message");
|
||||
map.put("parameters", params);
|
||||
|
||||
List<String> examples = new ArrayList<String>();
|
||||
examples.add("<email subject=\"Password reset confirmation\" html=html text=text>");
|
||||
map.put("examples", examples);
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import freemarker.core.Environment;
|
||||
import freemarker.template.SimpleScalar;
|
||||
import freemarker.template.TemplateDirectiveBody;
|
||||
import freemarker.template.TemplateException;
|
||||
import freemarker.template.TemplateModel;
|
||||
|
@ -44,12 +45,19 @@ public class UrlDirective extends BaseTemplateDirectiveModel {
|
|||
"The url directive doesn't allow nested content.");
|
||||
}
|
||||
|
||||
String path = params.get("path").toString();
|
||||
if (path == null) {
|
||||
Object o = params.get("path");
|
||||
if (o == null) {
|
||||
throw new TemplateModelException(
|
||||
"The url directive requires a value for parameter 'path'.");
|
||||
}
|
||||
|
||||
if (! ( o instanceof SimpleScalar)) {
|
||||
throw new TemplateModelException(
|
||||
"The url directive requires a string value for parameter 'path'.");
|
||||
}
|
||||
|
||||
String path = o.toString();
|
||||
|
||||
if (!path.startsWith("/")) {
|
||||
throw new TemplateModelException(
|
||||
"The url directive requires that the value of parameter 'path' is an absolute path starting with '/'.");
|
||||
|
@ -60,6 +68,7 @@ public class UrlDirective extends BaseTemplateDirectiveModel {
|
|||
out.write(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> help(String name) {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
|
||||
|
@ -77,6 +86,5 @@ public class UrlDirective extends BaseTemplateDirectiveModel {
|
|||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ public class WidgetDirective extends BaseTemplateDirectiveModel {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> help(String name) {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Confirmation that an password has been reset. -->
|
||||
<#-- Confirmation that a password has been reset. -->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Confirmation email for user account password reset -->
|
||||
|
||||
<#assign subject = "Reset password request" />
|
||||
|
||||
<#assign html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${subject}</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
${userAccount.firstName} ${userAccount.lastName}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Password successfully changed.</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Your new password associated with ${userAccount.emailAddress} has been changed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Thank you.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</#assign>
|
||||
|
||||
<#assign text>
|
||||
${userAccount.firstName} ${userAccount.lastName}
|
||||
|
||||
We received a request to reset the password for your account
|
||||
(${userAccount.emailAddress}).
|
||||
Please follow the instructions below to proceed with your password reset.
|
||||
|
||||
If you did not request this new account you can safely ignore this email.
|
||||
This request will expire if not acted upon for 30 days.
|
||||
|
||||
Paste the link below into your browser's address bar to reset your password
|
||||
using our secure server.
|
||||
|
||||
${passwordLink}
|
||||
|
||||
Thank you!
|
||||
</#assign>
|
||||
|
||||
<@email subject=subject html=html text=text />
|
Loading…
Add table
Reference in a new issue