NIHVIVO-2693 Add Freemarker user-defined directive for email and integrate into email messaging framework.

This commit is contained in:
ryounes 2011-06-14 12:34:39 +00:00
parent 9c9f7dfe57
commit 2fcff042e6
9 changed files with 260 additions and 18 deletions

View file

@ -200,7 +200,7 @@ public class UserAccountsEditPage extends UserAccountsPage {
userAccountsDao.updateUserAccount(userAccount);
strategy.notifyUser();
strategy.notifyUser(vreq);
}
public boolean wasPasswordEmailSent() {

View file

@ -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.
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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("&lt;email subject=\"Password reset confirmation\" html=html text=text&gt;");
map.put("examples", examples);
return map;
}
}

View file

@ -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;
}
}

View file

@ -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>();

View file

@ -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>

View file

@ -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 />