diff --git a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java index a0a91e22c32..432f45e1af9 100644 --- a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java @@ -25,7 +25,6 @@ import java.util.Map; import java.util.HashMap; import java.util.List; -import java.util.ResourceBundle; import java.util.Set; import java.util.logging.Logger; import javax.annotation.Resource; @@ -67,7 +66,7 @@ public class MailServiceBean implements java.io.Serializable { GroupServiceBean groupService; @EJB ConfirmEmailServiceBean confirmEmailService; - + private static final Logger logger = Logger.getLogger(MailServiceBean.class.getCanonicalName()); private static final String charset = "UTF-8"; @@ -88,10 +87,9 @@ public void sendMail(String host, String reply, String to, String subject, Strin String[] recipientStrings = to.split(","); InternetAddress[] recipients = new InternetAddress[recipientStrings.length]; try { - InternetAddress fromAddress=getSystemAddress(); - fromAddress.setPersonal(BundleUtil.getStringFromBundle("contact.delegation", Arrays.asList( - fromAddress.getPersonal(), reply)), charset); - msg.setFrom(fromAddress); + InternetAddress fromAddress = getSystemAddress(); + setContactDelegation(reply, fromAddress); + msg.setFrom(fromAddress); msg.setReplyTo(new Address[] {new InternetAddress(reply, charset)}); for (int i = 0; i < recipients.length; i++) { recipients[i] = new InternetAddress(recipientStrings[i], "", charset); @@ -109,7 +107,7 @@ public void sendMail(String host, String reply, String to, String subject, Strin me.printStackTrace(System.out); } } - + @Resource(name = "mail/notifyMailSession") private Session session; @@ -119,14 +117,13 @@ public boolean sendSystemEmail(String to, String subject, String messageText) { public boolean sendSystemEmail(String to, String subject, String messageText, boolean isHtmlContent) { - boolean sent = false; InternetAddress systemAddress = getSystemAddress(); - + String body = messageText + (isHtmlContent ? BundleUtil.getStringFromBundle("notification.email.closing.html", Arrays.asList(BrandingUtil.getSupportTeamEmailAddress(systemAddress), BrandingUtil.getSupportTeamName(systemAddress))) : BundleUtil.getStringFromBundle("notification.email.closing", Arrays.asList(BrandingUtil.getSupportTeamEmailAddress(systemAddress), BrandingUtil.getSupportTeamName(systemAddress)))); - + logger.fine("Sending email to " + to + ". Subject: <<<" + subject + ">>>. Body: " + body); try { MimeMessage msg = new MimeMessage(session); @@ -169,9 +166,9 @@ public boolean sendSystemEmail(String to, String subject, String messageText, bo } return sent; } - + private InternetAddress getSystemAddress() { - String systemEmail = settingsService.getValueForKey(Key.SystemEmail); + String systemEmail = settingsService.getValueForKey(Key.SystemEmail); return MailUtil.parseSystemAddress(systemEmail); } @@ -183,20 +180,19 @@ public void sendMail(String from, String to, String subject, String messageText) public void sendMail(String reply, String to, String subject, String messageText, Map extraHeaders) { try { MimeMessage msg = new MimeMessage(session); - //Always send from system address to avoid email being blocked - InternetAddress fromAddress=getSystemAddress(); + // Always send from system address to avoid email being blocked + InternetAddress fromAddress = getSystemAddress(); try { - fromAddress.setPersonal(BundleUtil.getStringFromBundle("contact.delegation", Arrays.asList( - fromAddress.getPersonal(), reply)), charset); + setContactDelegation(reply, fromAddress); } catch (UnsupportedEncodingException ex) { logger.severe(ex.getMessage()); } msg.setFrom(fromAddress); if (EMailValidator.isEmailValid(reply, null)) { - //But set the reply-to address to direct replies to the requested 'from' party if it is a valid email address + // But set the reply-to address to direct replies to the requested 'from' party if it is a valid email address msg.setReplyTo(new Address[] {new InternetAddress(reply)}); } else { - //Otherwise include the invalid 'from' address in the message + // Otherwise include the invalid 'from' address in the message messageText = "From: " + reply + "\n\n" + messageText; } msg.setSentDate(new Date()); @@ -221,12 +217,32 @@ public void sendMail(String reply, String to, String subject, String messageText me.printStackTrace(System.out); } } - - public Boolean sendNotificationEmail(UserNotification notification){ + + /** + * Set the contact delegation as "[dataverse team] on behalf of [user email]" + * @param reply The user's email address as give via the contact form + * @param fromAddress The system email address + * @throws UnsupportedEncodingException + */ + public void setContactDelegation(String reply, InternetAddress fromAddress) + throws UnsupportedEncodingException { + String personal = fromAddress.getPersonal() != null + ? fromAddress.getPersonal() + : BrandingUtil.getInstallationBrandName() != null + ? BrandingUtil.getInstallationBrandName() + : BundleUtil.getStringFromBundle("contact.delegation.default_personal"); + fromAddress.setPersonal( + BundleUtil.getStringFromBundle( + "contact.delegation", + Arrays.asList(personal, reply)), + charset + ); + } + + public Boolean sendNotificationEmail(UserNotification notification){ return sendNotificationEmail(notification, ""); } - - + public Boolean sendNotificationEmail(UserNotification notification, String comment) { return sendNotificationEmail(notification, comment, null, false); } @@ -235,7 +251,6 @@ public Boolean sendNotificationEmail(UserNotification notification, String comme return sendNotificationEmail(notification, comment, null, isHtmlContent); } - public Boolean sendNotificationEmail(UserNotification notification, String comment, AuthenticatedUser requestor, boolean isHtmlContent){ boolean retval = false; @@ -257,21 +272,20 @@ public Boolean sendNotificationEmail(UserNotification notification, String comme logger.warning("Skipping " + notification.getType() + " notification, because email address is null"); } return retval; - } private String getDatasetManageFileAccessLink(DataFile datafile){ return systemConfig.getDataverseSiteUrl() + "/permissions-manage-files.xhtml?id=" + datafile.getOwner().getId(); } - + private String getDatasetLink(Dataset dataset){ return systemConfig.getDataverseSiteUrl() + "/dataset.xhtml?persistentId=" + dataset.getGlobalIdString(); } - + private String getDatasetDraftLink(Dataset dataset){ return systemConfig.getDataverseSiteUrl() + "/dataset.xhtml?persistentId=" + dataset.getGlobalIdString() + "&version=DRAFT" + "&faces-redirect=true"; } - + private String getDataverseLink(Dataverse dataverse){ return systemConfig.getDataverseSiteUrl() + "/dataverse/" + dataverse.getAlias(); } @@ -333,20 +347,16 @@ private String getDvObjectTypeString(DvObject d) { } return ""; } - + public String getMessageTextBasedOnNotification(UserNotification userNotification, Object targetObject){ - return getMessageTextBasedOnNotification(userNotification, targetObject, ""); - } - + public String getMessageTextBasedOnNotification(UserNotification userNotification, Object targetObject, String comment) { return getMessageTextBasedOnNotification(userNotification, targetObject, comment, null); - } - public String getMessageTextBasedOnNotification(UserNotification userNotification, Object targetObject, String comment, AuthenticatedUser requestor) { - + public String getMessageTextBasedOnNotification(UserNotification userNotification, Object targetObject, String comment, AuthenticatedUser requestor) { String messageText = BundleUtil.getStringFromBundle("notification.email.greeting"); DatasetVersion version; Dataset dataset; @@ -480,7 +490,6 @@ public String getMessageTextBasedOnNotification(UserNotification userNotificatio case RETURNEDDS: version = (DatasetVersion) targetObject; pattern = BundleUtil.getStringFromBundle("notification.email.wasReturnedByReviewer"); - String optionalReturnReason = ""; /* FIXME @@ -494,11 +503,10 @@ public String getMessageTextBasedOnNotification(UserNotification userNotificatio version.getDataset().getOwner().getDisplayName(), getDataverseLink(version.getDataset().getOwner()), optionalReturnReason}; messageText += MessageFormat.format(pattern, paramArrayReturnedDataset); return messageText; - + case WORKFLOW_SUCCESS: version = (DatasetVersion) targetObject; pattern = BundleUtil.getStringFromBundle("notification.email.workflow.success"); - if (comment == null) { comment = BundleUtil.getStringFromBundle("notification.email.workflow.nullMessage"); } @@ -583,10 +591,10 @@ public String getMessageTextBasedOnNotification(UserNotification userNotificatio return ingestedCompletedWithErrorsMessage; } - + return ""; } - + private Object getObjectOfNotification (UserNotification userNotification){ switch (userNotification.getType()) { case ASSIGNROLE: @@ -631,10 +639,7 @@ private Object getObjectOfNotification (UserNotification userNotification){ } return null; } - - - private String getUserEmailAddress(UserNotification notification) { if (notification != null) { if (notification.getUser() != null) { @@ -646,9 +651,8 @@ private String getUserEmailAddress(UserNotification notification) { } } } - + logger.fine("no email address"); return null; } - } diff --git a/src/main/java/edu/harvard/iq/dataverse/branding/BrandingUtil.java b/src/main/java/edu/harvard/iq/dataverse/branding/BrandingUtil.java index 50661ee97fc..3cb071fe03f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/branding/BrandingUtil.java +++ b/src/main/java/edu/harvard/iq/dataverse/branding/BrandingUtil.java @@ -16,10 +16,9 @@ public class BrandingUtil { private static SettingsServiceBean settingsService; public static String getInstallationBrandName() { - String brandName = settingsService.getValueForKey(SettingsServiceBean.Key.InstallationName); - //Separate if statement simplifies test setup, otherwise could use the getValueForKey method with a default param - if(brandName==null) { + // Separate if statement simplifies test setup, otherwise could use the getValueForKey method with a default param + if (brandName == null) { brandName = dataverseService.getRootDataverseName(); } return brandName; @@ -38,7 +37,7 @@ public static String getSupportTeamName(InternetAddress systemAddress) { return personalName; } } - String rootDataverseName=dataverseService.getRootDataverseName(); + String rootDataverseName = dataverseService.getRootDataverseName(); if (rootDataverseName != null && !rootDataverseName.isEmpty()) { return rootDataverseName + " " + BundleUtil.getStringFromBundle("contact.support"); } diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 6b8ab6edcad..d22f6f6537f 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -705,6 +705,7 @@ notification.email.checksumfail.subject={0}: Your upload failed checksum validat notification.email.import.filesystem.subject=Dataset {0} has been successfully uploaded and verified notification.email.import.checksum.subject={0}: Your file checksum job has completed contact.delegation={0} on behalf of {1} +contact.delegation.default_personal=Dataverse Installation Admin notification.email.info.unavailable=Unavailable notification.email.apiTokenGenerated=Hello {0} {1},\n\nAPI Token has been generated. Please keep it secure as you would do with a password. notification.email.apiTokenGenerated.subject=API Token was generated diff --git a/src/test/java/edu/harvard/iq/dataverse/MailServiceBeanTest.java b/src/test/java/edu/harvard/iq/dataverse/MailServiceBeanTest.java new file mode 100644 index 00000000000..baeb54f6867 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/MailServiceBeanTest.java @@ -0,0 +1,103 @@ +package edu.harvard.iq.dataverse; + +import edu.harvard.iq.dataverse.branding.BrandingUtil; +import edu.harvard.iq.dataverse.settings.SettingsServiceBean; +import edu.harvard.iq.dataverse.util.MailUtil; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.mail.internet.InternetAddress; + +import java.io.UnsupportedEncodingException; + +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(MockitoExtension.class) +class MailServiceBeanTest { + + @Mock + DataverseServiceBean dataverseService; + @Mock + SettingsServiceBean settingsService; + + @Test + void setContactDelegation_withName() { + initBrandingUtilWithRootDataverse(null, null); + + InternetAddress fromAddress = MailUtil.parseSystemAddress("Foo Bar "); + MailServiceBean mailServiceBean = new MailServiceBean(); + try { + mailServiceBean.setContactDelegation("user@example.edu", fromAddress); + assertEquals( + "Foo Bar on behalf of user@example.edu", + fromAddress.getPersonal() + ); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + @Test + void setContactDelegation_withoutName_fromInstallationName() { + initBrandingUtilWithRootDataverse("LibraScholar Dataverse", null); + + InternetAddress fromAddress = MailUtil.parseSystemAddress("dataverse@dataverse.org"); + MailServiceBean mailServiceBean = new MailServiceBean(); + try { + mailServiceBean.setContactDelegation("user@example.edu", fromAddress); + assertEquals( + "LibraScholar Dataverse on behalf of user@example.edu", + fromAddress.getPersonal() + ); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + @Test + void setContactDelegation_withoutName_fromBranding() { + initBrandingUtilWithRootDataverse(null, "LibraScholar"); + + InternetAddress fromAddress = MailUtil.parseSystemAddress("dataverse@dataverse.org"); + MailServiceBean mailServiceBean = new MailServiceBean(); + try { + mailServiceBean.setContactDelegation("user@example.edu", fromAddress); + assertEquals( + "LibraScholar on behalf of user@example.edu", + fromAddress.getPersonal() + ); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + @Test + void setContactDelegation_withoutName_fromBundle() { + initBrandingUtilWithRootDataverse(null, null); + + InternetAddress fromAddress = MailUtil.parseSystemAddress("dataverse@dataverse.org"); + MailServiceBean mailServiceBean = new MailServiceBean(); + try { + mailServiceBean.setContactDelegation("user@example.edu", fromAddress); + assertEquals( + "Dataverse Installation Admin on behalf of user@example.edu", + fromAddress.getPersonal() + ); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + private void initBrandingUtilWithRootDataverse(String installationName, String rootDataverseName) { + Mockito.lenient() + .when(settingsService.getValueForKey(SettingsServiceBean.Key.InstallationName)) + .thenReturn(installationName); + Mockito.lenient() + .when(dataverseService.getRootDataverseName()) + .thenReturn(rootDataverseName); + BrandingUtil.injectServices(dataverseService, settingsService); + } +} \ No newline at end of file