diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPageStrategy.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPageStrategy.java index 036d314e2..3d546f96a 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPageStrategy.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPageStrategy.java @@ -57,8 +57,6 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage { private static class EmailStrategy extends UserAccountsAddPageStrategy { public static final String CREATE_PASSWORD_URL = "/accounts/createPassword"; - private static final String EMAIL_TEMPLATE_WITH_PASSWORD = "userAccounts-acctCreatedEmail.ftl"; - private static final String EMAIL_TEMPLATE_NO_PASSWORD = "userAccounts-acctCreatedExternalOnlyEmail.ftl"; private boolean sentEmail; @@ -100,15 +98,19 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage { body.put("userAccount", page.getAddedAccount()); body.put("passwordLink", buildCreatePasswordLink()); body.put("siteName", getSiteName()); - FreemarkerEmailMessage email = FreemarkerEmailFactory .createNewMessage(vreq); email.addRecipient(TO, page.getAddedAccount().getEmailAddress()); - email.setSubject(i18n.text("account_created_subject", getSiteName())); + String subject = i18n.text("account_created_subject", getSiteName()); + email.setSubject(subject); if (page.isExternalAuthOnly()) { - email.setTemplate(EMAIL_TEMPLATE_NO_PASSWORD); + body.put("subject", subject); + body.put("textMessage", i18n.text("acct_created_external_only_email_plain_text")); + body.put("htmlMessage", i18n.text("acct_created_external_only_email_html_text")); } else { - email.setTemplate(EMAIL_TEMPLATE_WITH_PASSWORD); + body.put("subject", subject); + body.put("textMessage", i18n.text("acct_created_email_plain_text")); + body.put("htmlMessage", i18n.text("acct_created_email_html_text")); } email.setBodyMap(body); email.processTemplate(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPageStrategy.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPageStrategy.java index d9ee8aa14..be364fb75 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPageStrategy.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPageStrategy.java @@ -56,8 +56,6 @@ 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-passwordResetPendingEmail.ftl"; - public static final String RESET_PASSWORD_URL = "/accounts/resetPassword"; private boolean resetPassword; @@ -107,11 +105,13 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage { body.put("userAccount", page.getUpdatedAccount()); body.put("passwordLink", buildResetPasswordLink()); body.put("siteName", getSiteName()); + body.put("subject", i18n.text("password_reset_pending_email_subject")); + body.put("textMessage",i18n.text("password_reset_pending_email_plain_text")); + body.put("htmlMessage", i18n.text("password_reset_pending_email_html_text")); FreemarkerEmailMessage email = FreemarkerEmailFactory .createNewMessage(vreq); email.addRecipient(TO, page.getUpdatedAccount().getEmailAddress()); - email.setTemplate(EMAIL_TEMPLATE); email.setBodyMap(body); email.processTemplate(); email.send(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsCreatePasswordPage.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsCreatePasswordPage.java index 68daa2d67..5ba3aba76 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsCreatePasswordPage.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsCreatePasswordPage.java @@ -26,8 +26,6 @@ public class UserAccountsCreatePasswordPage extends .getLog(UserAccountsCreatePasswordPage.class); private static final String TEMPLATE_NAME = "userAccounts-createPassword.ftl"; - private static final String EMAIL_TEMPLATE = "userAccounts-passwordCreatedEmail.ftl"; - public UserAccountsCreatePasswordPage(VitroRequest vreq) { super(vreq); } @@ -73,8 +71,11 @@ public class UserAccountsCreatePasswordPage extends FreemarkerEmailMessage email = FreemarkerEmailFactory .createNewMessage(vreq); email.addRecipient(TO, userAccount.getEmailAddress()); - email.setSubject(i18n.text("password_created_subject", getSiteName())); - email.setTemplate(EMAIL_TEMPLATE); + final String subject = i18n.text("password_created_subject", getSiteName()); + email.setSubject(subject); + body.put("subject", subject); + body.put("textMessage", i18n.text("password_created_email_plain_text")); + body.put("htmlMessage", i18n.text("password_created_email_html_text")); email.setBodyMap(body); email.processTemplate(); email.send(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPageStrategy.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPageStrategy.java index 447d2d223..1b9486e78 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPageStrategy.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPageStrategy.java @@ -52,8 +52,6 @@ public abstract class UserAccountsFirstTimeExternalPageStrategy extends public static class EmailStrategy extends UserAccountsFirstTimeExternalPageStrategy { - private static final String EMAIL_TEMPLATE = "userAccounts-firstTimeExternalEmail.ftl"; - public EmailStrategy(VitroRequest vreq, UserAccountsFirstTimeExternalPage page) { super(vreq, page); @@ -73,8 +71,11 @@ public abstract class UserAccountsFirstTimeExternalPageStrategy extends FreemarkerEmailMessage email = FreemarkerEmailFactory .createNewMessage(vreq); email.addRecipient(TO, ua.getEmailAddress()); - email.setSubject(i18n.text("account_created_subject", getSiteName())); - email.setTemplate(EMAIL_TEMPLATE); + final String subject = i18n.text("account_created_subject", getSiteName()); + email.setSubject(subject); + body.put("subject", subject); + body.put("textMessage", i18n.text("first_time_external_email_plain_text")); + body.put("htmlMessage", i18n.text("first_time_external_email_html_text")); email.setBodyMap(body); email.processTemplate(); email.send(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPageStrategy.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPageStrategy.java index ca895cab8..34481efbe 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPageStrategy.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPageStrategy.java @@ -108,8 +108,6 @@ public abstract class UserAccountsMyAccountPageStrategy extends private static final String ERROR_WRONG_PASSWORD_LENGTH = "errorPasswordIsWrongLength"; private static final String ERROR_PASSWORDS_DONT_MATCH = "errorPasswordsDontMatch"; - private static final String EMAIL_TEMPLATE = "userAccounts-confirmEmailChangedEmail.ftl"; - private final String originalEmail; private String newPassword; @@ -179,8 +177,11 @@ public abstract class UserAccountsMyAccountPageStrategy extends FreemarkerEmailMessage email = FreemarkerEmailFactory .createNewMessage(vreq); email.addRecipient(TO, page.getUserAccount().getEmailAddress()); - email.setSubject(i18n.text("email_changed_subject", getSiteName())); - email.setTemplate(EMAIL_TEMPLATE); + final String subject = i18n.text("email_changed_subject", getSiteName()); + email.setSubject(subject); + body.put("subject", subject); + body.put("textMessage", i18n.text("confirm_email_changed_email_plain_text")); + body.put("htmlMessage", i18n.text("confirm_email_changed_email_html_text")); email.setBodyMap(body); email.processTemplate(); email.send(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsResetPasswordPage.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsResetPasswordPage.java index f865cbe94..8e22ae043 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsResetPasswordPage.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsResetPasswordPage.java @@ -26,8 +26,6 @@ public class UserAccountsResetPasswordPage extends UserAccountsPasswordBasePage private static final String TEMPLATE_NAME = "userAccounts-resetPassword.ftl"; - private static final String EMAIL_TEMPLATE = "userAccounts-passwordResetCompleteEmail.ftl"; - protected UserAccountsResetPasswordPage(VitroRequest vreq) { super(vreq); } @@ -68,14 +66,16 @@ public class UserAccountsResetPasswordPage extends UserAccountsPasswordBasePage private void notifyUser() { Map body = new HashMap(); + FreemarkerEmailMessage email = FreemarkerEmailFactory.createNewMessage(vreq); + final String subject = i18n.text("password_changed_subject"); + email.setSubject(subject); + body.put("userAccount", userAccount); body.put("siteName", getSiteName()); - - FreemarkerEmailMessage email = FreemarkerEmailFactory - .createNewMessage(vreq); + body.put("subject", subject); + body.put("textMessage", i18n.text("password_reset_complete_email_plain_text")); + body.put("htmlMessage", i18n.text("password_reset_complete_email_html_text")); email.addRecipient(TO, userAccount.getEmailAddress()); - email.setSubject(i18n.text("password_changed_subject")); - email.setTemplate(EMAIL_TEMPLATE); email.setBodyMap(body); email.processTemplate(); email.send(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java index 50f54e2e0..cd416b931 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java @@ -8,7 +8,7 @@ import static javax.mail.Message.RecipientType.TO; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; -import java.nio.charset.Charset; +import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -41,6 +41,8 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.Tem import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage; import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; +import edu.cornell.mannlib.vitro.webapp.i18n.I18n; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.User; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.MainMenu; @@ -67,7 +69,6 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { // error templates ERROR_DISPLAY("error-display.ftl"), - ERROR_EMAIL("error-email.ftl"), ERROR_MESSAGE("error-message.ftl"), STANDARD_ERROR("error-standard.ftl"), TITLED_ERROR_MESSAGE("error-titled.ftl"), @@ -161,7 +162,8 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { } adminErrorData.put("cause", cause); - adminErrorData.put("datetime", new Date()); + SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); + adminErrorData.put("datetime", dateformat.format(new Date())); templateMap.put("errorOnHomePage", this instanceof HomePageController); @@ -175,7 +177,11 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { } else if (FreemarkerEmailFactory.isConfigured(vreq)) { FreemarkerEmailMessage email = FreemarkerEmailFactory.createNewMessage(vreq); email.addRecipient(TO, email.getReplyToAddress()); - email.setTemplate(Template.ERROR_EMAIL.toString()); + I18nBundle i18n = I18n.bundle(vreq); + addSiteName(vreq, adminErrorData); + adminErrorData.put("subject", i18n.text("application_error_email_subject")); + adminErrorData.put("textMessage", i18n.text("application_error_email_plain_text")); + adminErrorData.put("htmlMessage", i18n.text("application_error_email_html_text")); email.setBodyMap(adminErrorData); email.processTemplate(); sentEmail = email.send(); @@ -193,6 +199,16 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { } } + private void addSiteName(VitroRequest vreq, Map adminErrorData) { + try { + ApplicationBean appBean = vreq.getAppBean(); + String appName = appBean.getApplicationName(); + adminErrorData.put("siteName", appName); + } catch (Exception e) { + log.error(e,e); + } + } + @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java index ee5a9ef17..c361955ec 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java @@ -24,24 +24,19 @@ import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import org.apache.commons.lang3.StringUtils; 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.web.directives.EmailDirective; 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 * from a Freemarker template. * - * The template must call the @email directive, which may provide the subject - * line, the HTML content, and the plain text content. If these values are not - * provided by the directive, they default to empty strings, or to values that - * were set by the controller. - * - * @see EmailDirective */ public class FreemarkerEmailMessage { private static final Log log = LogFactory @@ -56,7 +51,6 @@ public class FreemarkerEmailMessage { private InternetAddress fromAddress = null; private String subject = ""; - private String templateName = ""; private String htmlContent = ""; private String textContent = ""; private Map bodyMap = Collections.emptyMap(); @@ -124,10 +118,6 @@ public class FreemarkerEmailMessage { this.textContent = nonNull(textContent, ""); } - public void setTemplate(String templateName) { - this.templateName = nonNull(templateName, ""); - } - public void setBodyMap(Map body) { if (body == null) { this.bodyMap = Collections.emptyMap(); @@ -137,16 +127,52 @@ public class FreemarkerEmailMessage { } public void processTemplate() { - bodyMap.put("email", new EmailDirective(this)); - try { - config.getTemplate(templateName).process(bodyMap, - new StringWriter()); + addDefaultBodyMapValues(); + StringWriter writer = new StringWriter(); + new Template(null, getInlineVariable("subject"), config).process(bodyMap, writer); + subject = writer.toString(); + writer.getBuffer().setLength(0); + new Template(null, getEmailTemplate(), config).process(bodyMap, writer); + htmlContent = writer.toString(); + writer.getBuffer().setLength(0); + new Template(null, getInlineVariable("textMessage"), config).process(bodyMap, writer); + textContent = writer.toString(); } catch (TemplateException | IOException e) { log.error(e, e); } } + private void addDefaultBodyMapValues() { + if (!bodyMap.containsKey("subject")) { + if (StringUtils.isBlank(subject)) { + bodyMap.put("subject", "No subject defined"); + } + bodyMap.put("subject", subject); + } + if (!bodyMap.containsKey("textMessage")) { + bodyMap.put("textMessage", "No text message defined"); + } + if (!bodyMap.containsKey("htmlMessage")) { + bodyMap.put("htmlMessage", "No html message defined"); + } + } + + private String getInlineVariable(String name) { + return "<@" + name + "?interpret />"; + } + + private String getEmailTemplate() { + return "\n" + + " \n" + + " <@subject?interpret />\n" + + " \n" + + " \n" + + " <@htmlMessage?interpret />\n" + + " \n" + + ""; + } + public boolean send() { try { MimeMessage msg = new MimeMessage(mailSession); @@ -182,8 +208,7 @@ public class FreemarkerEmailMessage { } msg.setSentDate(new Date()); - - Transport.send(msg); + sendMessage(msg); return true; } catch (MessagingException e) { log.error("Failed to send message.", e); @@ -191,6 +216,19 @@ public class FreemarkerEmailMessage { } } + private void sendMessage(MimeMessage msg) { + Thread thread = new Thread() { + public void run() { + try { + Transport.send(msg); + } catch (MessagingException e) { + log.error(e, e); + } + } + }; + thread.start(); + } + private void addBodyPart(MimeMultipart content, String textBody, String type) throws MessagingException { MimeBodyPart bodyPart = new MimeBodyPart(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/directives/EmailDirective.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/directives/EmailDirective.java deleted file mode 100644 index 4b31d7d77..000000000 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/directives/EmailDirective.java +++ /dev/null @@ -1,82 +0,0 @@ -/* $This file is distributed under the terms of the license in LICENSE$ */ - -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 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.TemplateDirectiveBody; -import freemarker.template.TemplateException; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -/** - * Process the inputs for a FreemarkerEmailMessage. - * - * @see FreemarkerEmailMessage - */ -public class EmailDirective extends BaseTemplateDirectiveModel { - - private static final Log log = LogFactory.getLog(EmailDirective.class); - - private final FreemarkerEmailMessage message; - - public EmailDirective(FreemarkerEmailMessage message) { - this.message = message; - } - - @Override - public void execute(Environment env, Map params, TemplateModel[] loopVars, - TemplateDirectiveBody body) throws TemplateException, IOException { - - String subject = getOptionalSimpleScalarParameter(params, "subject"); - if (subject != null) { - message.setSubject(subject); - } - - String htmlContent = getOptionalSimpleScalarParameter(params, "html"); - if (htmlContent != null) { - message.setHtmlContent(htmlContent); - } - - String textContent = getOptionalSimpleScalarParameter(params, "text"); - if (textContent != null) { - message.setTextContent(textContent); - } - - if ((htmlContent == null) && (textContent == null)) { - throw new TemplateModelException("The email directive must have " - + "either a 'html' parameter or a 'text' parameter."); - } - } - - @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 (optional)"); - params.put("html", "HTML version of email message (optional)"); - params.put("text", "Plain text version of email message (optional)"); - map.put("parameters", params); - - List examples = new ArrayList(); - examples.add("<email subject=\"Password reset confirmation\" html=html text=text>"); - examples.add("<email html=html text=text>"); - map.put("examples", examples); - - return map; - } -} diff --git a/webapp/src/main/webapp/templates/freemarker/body/error/error-email.ftl b/webapp/src/main/webapp/templates/freemarker/body/error/error-email.ftl deleted file mode 100644 index fa804266e..000000000 --- a/webapp/src/main/webapp/templates/freemarker/body/error/error-email.ftl +++ /dev/null @@ -1,62 +0,0 @@ -<#-- $This file is distributed under the terms of the license in LICENSE$ --> - -<#-- Template for email message sent to site administrator when an error occurs on the site. --> - -<#assign subject = "${i18n().error_occurred(siteName!)}" /> - -<#assign datetime = datetime?string("yyyy-MM-dd HH:mm:ss zzz")> - -<#assign html> - - - ${subject!} - - -

- ${i18n().error_occurred_at(siteName!,datetime!)} -

- -

- ${i18n().requested_url}: ${requestedUrl!} -

- -

- <#if errorMessage?has_content> - ${i18n().error_message}: ${errorMessage!} - -

- -

- ${i18n().stack_trace} (${i18n().trace_available(siteName!)}): -

${stackTrace!}
-

- - <#if cause?has_content> -

${i18n().caused_by}: -

${cause!}
-

- - - - - - -<#assign text> -${i18n().error_occurred_at(siteName!,datetime!)} - -${i18n().requested_url}: ${requestedUrl!} - -<#if errorMessage?has_content> - ${i18n().error_message}: ${errorMessage!} - - -${i18n().stack_trace} (${i18n().trace_available(siteName!)}): -${stackTrace!} - -<#if cause?has_content> -${i18n().caused_by}: -${cause!} - - - -<@email subject=subject html=html text=text />