Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 48 additions & 44 deletions src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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";
Expand All @@ -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);
Expand All @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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);
}

Expand All @@ -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<Object, Object> 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());
Expand All @@ -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);
}
Expand All @@ -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;
Expand All @@ -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();
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -480,7 +490,6 @@ public String getMessageTextBasedOnNotification(UserNotification userNotificatio
case RETURNEDDS:
version = (DatasetVersion) targetObject;
pattern = BundleUtil.getStringFromBundle("notification.email.wasReturnedByReviewer");

String optionalReturnReason = "";
/*
FIXME
Expand All @@ -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");
}
Expand Down Expand Up @@ -583,10 +591,10 @@ public String getMessageTextBasedOnNotification(UserNotification userNotificatio

return ingestedCompletedWithErrorsMessage;
}

return "";
}

private Object getObjectOfNotification (UserNotification userNotification){
switch (userNotification.getType()) {
case ASSIGNROLE:
Expand Down Expand Up @@ -631,10 +639,7 @@ private Object getObjectOfNotification (UserNotification userNotification){
}
return null;
}




private String getUserEmailAddress(UserNotification notification) {
if (notification != null) {
if (notification.getUser() != null) {
Expand All @@ -646,9 +651,8 @@ private String getUserEmailAddress(UserNotification notification) {
}
}
}

logger.fine("no email address");
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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");
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/propertyFiles/Bundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
103 changes: 103 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/MailServiceBeanTest.java
Original file line number Diff line number Diff line change
@@ -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 <foo@bar.org>");
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);
}
}