diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPage.java index c939dfe24..6151d7d32 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPage.java @@ -200,7 +200,7 @@ public class UserAccountsEditPage extends UserAccountsPage { userAccountsDao.updateUserAccount(userAccount); - strategy.notifyUser(); + strategy.notifyUser(vreq); } public boolean wasPasswordEmailSent() { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPageStrategy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPageStrategy.java index c174f8288..d06105c6b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPageStrategy.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPageStrategy.java @@ -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 body = new HashMap(); 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. } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java index fed74cbe0..6371bc0e6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java @@ -306,11 +306,18 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { */ public static Map getDirectives() { Map map = new HashMap(); - 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 getDirectivesForAllEnvironments() { + Map map = new HashMap(); + 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; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java index 3bc9115cf..72fb702d5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java @@ -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(body)); } } + + public void processTemplate(VitroRequest vreq, String templateName, Map 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); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/EmailDirective.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/EmailDirective.java new file mode 100644 index 000000000..f3d75523b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/EmailDirective.java @@ -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 help(String name) { + Map map = new LinkedHashMap(); + + map.put("effect", "Create an email message from the parameters set in the invoking template."); + + Map params = new HashMap(); + 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 examples = new ArrayList(); + examples.add("<email subject=\"Password reset confirmation\" html=html text=text>"); + map.put("examples", examples); + + return map; + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/UrlDirective.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/UrlDirective.java index 85a59a7cd..9edf3ff85 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/UrlDirective.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/UrlDirective.java @@ -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 help(String name) { Map map = new LinkedHashMap(); @@ -77,6 +86,5 @@ public class UrlDirective extends BaseTemplateDirectiveModel { return map; } - } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/WidgetDirective.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/WidgetDirective.java index 654f5cecc..dff8eae6c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/WidgetDirective.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/WidgetDirective.java @@ -94,6 +94,7 @@ public class WidgetDirective extends BaseTemplateDirectiveModel { } + @Override public Map help(String name) { Map map = new LinkedHashMap(); diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetEmail-html.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetEmail-html.ftl index 5212fbebb..49c4eb531 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetEmail-html.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetEmail-html.ftl @@ -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. --> diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-resetPasswordEmail.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-resetPasswordEmail.ftl new file mode 100644 index 000000000..ca1e84abc --- /dev/null +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-resetPasswordEmail.ftl @@ -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> + + + ${subject} + + +

+ ${userAccount.firstName} ${userAccount.lastName} +

+ +

+ Password successfully changed. +

+ +

+ Your new password associated with ${userAccount.emailAddress} has been changed. +

+ +

+ Thank you. +

+ + + + +<#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! + + +<@email subject=subject html=html text=text /> \ No newline at end of file