diff --git a/pom.xml b/pom.xml index b6ea621..06e2616 100644 --- a/pom.xml +++ b/pom.xml @@ -60,6 +60,10 @@ org.springframework.boot spring-boot-starter-security + + org.springframework.boot + spring-boot-starter-mail + org.springdoc springdoc-openapi-ui diff --git a/src/main/java/uk/ac/ebi/eva/submission/config/AppConfig.java b/src/main/java/uk/ac/ebi/eva/submission/config/AppConfig.java new file mode 100644 index 0000000..74514c4 --- /dev/null +++ b/src/main/java/uk/ac/ebi/eva/submission/config/AppConfig.java @@ -0,0 +1,18 @@ +package uk.ac.ebi.eva.submission.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; + +@Configuration +public class AppConfig { + + @Bean + public JavaMailSender javaMailService() { + JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl(); + javaMailSender.setHost("smtp.ebi.ac.uk"); + javaMailSender.setPort(25); + return javaMailSender; + } +} diff --git a/src/main/java/uk/ac/ebi/eva/submission/controller/submissionws/SubmissionController.java b/src/main/java/uk/ac/ebi/eva/submission/controller/submissionws/SubmissionController.java index 251ec70..1d45f07 100644 --- a/src/main/java/uk/ac/ebi/eva/submission/controller/submissionws/SubmissionController.java +++ b/src/main/java/uk/ac/ebi/eva/submission/controller/submissionws/SubmissionController.java @@ -17,6 +17,7 @@ import uk.ac.ebi.eva.submission.controller.BaseController; import uk.ac.ebi.eva.submission.entity.Submission; import uk.ac.ebi.eva.submission.entity.SubmissionAccount; +import uk.ac.ebi.eva.submission.model.SubmissionStatus; import uk.ac.ebi.eva.submission.service.LsriTokenService; import uk.ac.ebi.eva.submission.service.SubmissionService; import uk.ac.ebi.eva.submission.service.WebinTokenService; @@ -87,6 +88,7 @@ public ResponseEntity markSubmissionUploaded(@RequestHeader("Authorization") } Submission submission = this.submissionService.markSubmissionUploaded(submissionId); + submissionService.sendMailNotificationForStatusUpdate(submissionAccount, submissionId, SubmissionStatus.UPLOADED, true); return new ResponseEntity<>(stripUserDetails(submission), HttpStatus.OK); } diff --git a/src/main/java/uk/ac/ebi/eva/submission/service/SubmissionService.java b/src/main/java/uk/ac/ebi/eva/submission/service/SubmissionService.java index ab54971..b5fd2db 100644 --- a/src/main/java/uk/ac/ebi/eva/submission/service/SubmissionService.java +++ b/src/main/java/uk/ac/ebi/eva/submission/service/SubmissionService.java @@ -2,13 +2,16 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import uk.ac.ebi.eva.submission.exception.SubmissionDoesNotExistException; import uk.ac.ebi.eva.submission.entity.Submission; import uk.ac.ebi.eva.submission.entity.SubmissionAccount; +import uk.ac.ebi.eva.submission.exception.SubmissionDoesNotExistException; import uk.ac.ebi.eva.submission.model.SubmissionStatus; import uk.ac.ebi.eva.submission.repository.SubmissionAccountRepository; import uk.ac.ebi.eva.submission.repository.SubmissionDetailsRepository; import uk.ac.ebi.eva.submission.repository.SubmissionRepository; +import uk.ac.ebi.eva.submission.util.EmailNotificationHelper; +import uk.ac.ebi.eva.submission.util.HTMLHelper; +import uk.ac.ebi.eva.submission.util.MailSender; import java.time.LocalDateTime; import java.util.Optional; @@ -25,17 +28,24 @@ public class SubmissionService { private final GlobusDirectoryProvisioner globusDirectoryProvisioner; + private final MailSender mailSender; + @Value("${globus.uploadHttpDomain}") private String uploadHttpDomain; + private EmailNotificationHelper emailHelper; + public SubmissionService(SubmissionRepository submissionRepository, SubmissionAccountRepository submissionAccountRepository, SubmissionDetailsRepository submissionDetailsRepository, - GlobusDirectoryProvisioner globusDirectoryProvisioner) { + GlobusDirectoryProvisioner globusDirectoryProvisioner, + MailSender mailSender, EmailNotificationHelper emailHelper) { this.submissionRepository = submissionRepository; this.submissionAccountRepository = submissionAccountRepository; this.submissionDetailsRepository = submissionDetailsRepository; this.globusDirectoryProvisioner = globusDirectoryProvisioner; + this.mailSender = mailSender; + this.emailHelper = emailHelper; } public Submission initiateSubmission(SubmissionAccount submissionAccount) { @@ -45,7 +55,7 @@ public Submission initiateSubmission(SubmissionAccount submissionAccount) { Optional optSubmissionAccount = submissionAccountRepository.findById(submissionAccount.getId()); // if the user account is not present or if its primary email has changed, save/update the user account - if (!optSubmissionAccount.isPresent() || optSubmissionAccount.get().getPrimaryEmail() != submissionAccount.getPrimaryEmail()) { + if (!optSubmissionAccount.isPresent() || !optSubmissionAccount.get().getPrimaryEmail().equals(submissionAccount.getPrimaryEmail())) { submissionAccountRepository.save(submissionAccount); } @@ -85,9 +95,17 @@ public boolean checkUserHasAccessToSubmission(SubmissionAccount account, String Optional optSubmission = submissionRepository.findById(submissionId); if (optSubmission.isPresent()) { SubmissionAccount submissionAccount = optSubmission.get().getSubmissionAccount(); - return submissionAccount.getId() == account.getId(); + return submissionAccount.getId().equals(account.getId()); } else { throw new SubmissionDoesNotExistException("Given submission with id " + submissionId + " does not exist"); } } + + public void sendMailNotificationForStatusUpdate(SubmissionAccount submissionAccount, String submissionId, + SubmissionStatus submissionStatus, boolean success) { + String sendTo = submissionAccount.getPrimaryEmail(); + String subject = emailHelper.getSubjectForSubmissionStatusUpdate(submissionStatus, success); + String body = emailHelper.getTextForSubmissionStatusUpdate(submissionAccount, submissionId, submissionStatus, success); + mailSender.sendEmail(sendTo, subject, body); + } } diff --git a/src/main/java/uk/ac/ebi/eva/submission/util/EmailNotificationHelper.java b/src/main/java/uk/ac/ebi/eva/submission/util/EmailNotificationHelper.java new file mode 100644 index 0000000..76146d7 --- /dev/null +++ b/src/main/java/uk/ac/ebi/eva/submission/util/EmailNotificationHelper.java @@ -0,0 +1,58 @@ +package uk.ac.ebi.eva.submission.util; + +import org.springframework.stereotype.Component; +import uk.ac.ebi.eva.submission.entity.SubmissionAccount; +import uk.ac.ebi.eva.submission.model.SubmissionStatus; + +@Component +public class EmailNotificationHelper { + private static final String EVA_HELPDESK_EMAIL = "eva-helpdesk@ebi.ac.uk"; + + public String getSubjectForSubmissionStatusUpdate(SubmissionStatus submissionStatus, boolean success) { + String result = (success == true) ? "SUCCESS" : "FAILED"; + return String.format("EVA Submission Update: %s %s", submissionStatus, result); + } + + public String getTextForSubmissionStatusUpdate(SubmissionAccount submissionAccount, String submissionId, + SubmissionStatus submissionStatus, boolean success) { + String result; + String resultColor; + if (success) { + result = "SUCCESS"; + resultColor = "green"; + } else { + result = "FAILED"; + resultColor = "red"; + } + + String notificationText = new HTMLHelper() + .addText("Dear " + submissionAccount.getFirstName() + ",") + .addGap(1) + .addText("Here is the update for your submission: ") + .addGap(1) + .addText("submission ID: " + submissionId) + .addLineBreak() + .addText("Submission Status: " + submissionStatus) + .addLineBreak() + .addText("Result: ") + .addBoldTextWithColor(result, resultColor) + .addGap(2) + .build(); + + notificationText += getNotificationFooter(); + + return notificationText; + } + + public String getNotificationFooter() { + return new HTMLHelper() + .addTextWithSize("Please don't reply to this email.", 10) + .addLineBreak() + .addTextWithSize("For any issues/support please contact us at ", 10) + .addEmailLinkWithSize(EVA_HELPDESK_EMAIL, EVA_HELPDESK_EMAIL, 10) + .addLineBreak() + .addTextWithSize("European Variation Archive: EMBL-EBI", 10) + .build(); + + } +} diff --git a/src/main/java/uk/ac/ebi/eva/submission/util/HTMLHelper.java b/src/main/java/uk/ac/ebi/eva/submission/util/HTMLHelper.java new file mode 100644 index 0000000..78997bf --- /dev/null +++ b/src/main/java/uk/ac/ebi/eva/submission/util/HTMLHelper.java @@ -0,0 +1,66 @@ +package uk.ac.ebi.eva.submission.util; + +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class HTMLHelper { + private final StringBuilder htmlBuilder; + + public HTMLHelper() { + htmlBuilder = new StringBuilder(); + } + + public HTMLHelper addLineBreak() { + htmlBuilder.append("
"); + return this; + } + + public HTMLHelper addGap(int count) { + htmlBuilder.append(IntStream.range(0, count+1).boxed().map(i -> "
").collect(Collectors.joining(""))); + return this; + } + + public HTMLHelper addText(String text) { + htmlBuilder.append(text); + return this; + } + + public HTMLHelper addTextWithSize(String text, int size) { + htmlBuilder.append("" + text + ""); + return this; + } + + public HTMLHelper addTextWithColor(String text, String color) { + htmlBuilder.append("" + text + ""); + return this; + } + + public HTMLHelper addBoldText(String text) { + htmlBuilder.append("" + text + ""); + return this; + } + + public HTMLHelper addLink(String url, String text) { + htmlBuilder.append("" + text + ""); + return this; + } + + public HTMLHelper addEmailLink(String email, String text) { + htmlBuilder.append("" + text + ""); + return this; + } + + public HTMLHelper addEmailLinkWithSize(String email, String text, int size) { + htmlBuilder.append(" " + text + " "); + return this; + } + + public HTMLHelper addBoldTextWithColor(String text, String color) { + htmlBuilder.append("" + text + ""); + return this; + } + + public String build() { + return htmlBuilder.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/uk/ac/ebi/eva/submission/util/MailSender.java b/src/main/java/uk/ac/ebi/eva/submission/util/MailSender.java new file mode 100644 index 0000000..1715ad6 --- /dev/null +++ b/src/main/java/uk/ac/ebi/eva/submission/util/MailSender.java @@ -0,0 +1,41 @@ +package uk.ac.ebi.eva.submission.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Component; + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; + +@Component +public class MailSender { + private final Logger logger = LoggerFactory.getLogger(MailSender.class); + private final JavaMailSender javaMailSender; + private final String DEFAULT_SENDER = "eva_submissions@ebi.ac.uk"; + + @Autowired + MailSender(JavaMailSender javaMailSender) { + this.javaMailSender = javaMailSender; + } + + public void sendEmail(String to, String subject, String body) { + sendEmail(DEFAULT_SENDER, to, subject, body); + } + + public void sendEmail(String from, String to, String subject, String body) { + MimeMessage message = javaMailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message); + try { + helper.setFrom(from); + helper.setTo(to); + helper.setSubject(subject); + helper.setText(body, true); + javaMailSender.send(message); + } catch (MessagingException e) { + logger.error("Error sending mail: " + e); + } + } +} \ No newline at end of file diff --git a/src/test/java/uk/ac/ebi/eva/submission/integration/SubmissionWSIntegrationTest.java b/src/test/java/uk/ac/ebi/eva/submission/integration/SubmissionWSIntegrationTest.java index 9bdf97d..51516ed 100644 --- a/src/test/java/uk/ac/ebi/eva/submission/integration/SubmissionWSIntegrationTest.java +++ b/src/test/java/uk/ac/ebi/eva/submission/integration/SubmissionWSIntegrationTest.java @@ -26,6 +26,7 @@ import uk.ac.ebi.eva.submission.service.LoginMethod; import uk.ac.ebi.eva.submission.service.LsriTokenService; import uk.ac.ebi.eva.submission.service.WebinTokenService; +import uk.ac.ebi.eva.submission.util.MailSender; import java.time.LocalDateTime; import java.util.ArrayList; @@ -76,6 +77,9 @@ public class SubmissionWSIntegrationTest { @MockBean private GlobusDirectoryProvisioner globusDirectoryProvisioner; + @MockBean + private MailSender mailSender; + @Container static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer<>("postgres:9.6") .withInitScript("init.sql"); @@ -230,6 +234,7 @@ public void testMarkSubmissionUploaded() throws Exception { String userToken = "webinUserToken"; SubmissionAccount submissionAccount = getWebinUserAccount(); when(webinTokenService.getWebinUserAccountFromToken(anyString())).thenReturn(submissionAccount); + doNothing().when(mailSender).sendEmail(anyString(), anyString(), anyString()); String submissionId = createNewSubmissionEntry(submissionAccount); diff --git a/src/test/java/uk/ac/ebi/eva/submission/unit/EmailNotificationHelperTest.java b/src/test/java/uk/ac/ebi/eva/submission/unit/EmailNotificationHelperTest.java new file mode 100644 index 0000000..647e97d --- /dev/null +++ b/src/test/java/uk/ac/ebi/eva/submission/unit/EmailNotificationHelperTest.java @@ -0,0 +1,87 @@ +package uk.ac.ebi.eva.submission.unit; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import uk.ac.ebi.eva.submission.entity.SubmissionAccount; +import uk.ac.ebi.eva.submission.model.SubmissionStatus; +import uk.ac.ebi.eva.submission.service.LoginMethod; +import uk.ac.ebi.eva.submission.util.EmailNotificationHelper; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class EmailNotificationHelperTest { + private EmailNotificationHelper emailNotificationHelper; + + @BeforeEach + public void setup() { + emailNotificationHelper = new EmailNotificationHelper(); + } + + @Test + public void testGetSubjectForSubmissionStatusUpdate() { + String expectedSubject = "EVA Submission Update: UPLOADED SUCCESS"; + String actualSubject = emailNotificationHelper.getSubjectForSubmissionStatusUpdate(SubmissionStatus.UPLOADED, true); + + assertEquals(expectedSubject, actualSubject); + } + + @Test + public void testGetTextForSubmissionStatusUpdateSuccess() { + SubmissionAccount submissionAccount = new SubmissionAccount("johndoe@example.com", + LoginMethod.WEBIN.toString(), "John", "Doe", "john@example.com"); + String expectedText = "Dear John," + + "

" + + "Here is the update for your submission: " + + "

" + + "submission ID: 12345
" + + "Submission Status: UPLOADED
" + + "Result: SUCCESS" + + "


" + + "Please don't reply to this email.
" + + "For any issues/support please contact us at " + + " eva-helpdesk@ebi.ac.uk " + + "
European Variation Archive: EMBL-EBI"; + + String actualText = emailNotificationHelper.getTextForSubmissionStatusUpdate(submissionAccount, + "12345", SubmissionStatus.UPLOADED, true); + + assertEquals(expectedText, actualText); + } + + @Test + public void testGetTextForSubmissionStatusUpdateFailure() { + SubmissionAccount submissionAccount = new SubmissionAccount("johndoe@example.com", + LoginMethod.WEBIN.toString(), "John", "Doe", "john@example.com"); + String expectedText = "Dear John," + + "

" + + "Here is the update for your submission: " + + "

" + + "submission ID: 12345
" + + "Submission Status: UPLOADED
" + + "Result: FAILED" + + "


" + + "Please don't reply to this email.
" + + "For any issues/support please contact us at " + + " eva-helpdesk@ebi.ac.uk " + + "
European Variation Archive: EMBL-EBI"; + + String actualText = emailNotificationHelper.getTextForSubmissionStatusUpdate(submissionAccount, + "12345", SubmissionStatus.UPLOADED, false); + + assertEquals(expectedText, actualText); + } + + @Test + public void testGetNotificationFooter(){ + String expectedFooter = "Please don't reply to this email.
" + + "For any issues/support please contact us at " + + " eva-helpdesk@ebi.ac.uk " + + "
European Variation Archive: EMBL-EBI"; + + String actualFooter = emailNotificationHelper.getNotificationFooter(); + + assertEquals(expectedFooter, actualFooter); + } + +} + diff --git a/src/test/java/uk/ac/ebi/eva/submission/unit/HTMLHelperTest.java b/src/test/java/uk/ac/ebi/eva/submission/unit/HTMLHelperTest.java new file mode 100644 index 0000000..5f89dc4 --- /dev/null +++ b/src/test/java/uk/ac/ebi/eva/submission/unit/HTMLHelperTest.java @@ -0,0 +1,109 @@ +package uk.ac.ebi.eva.submission.unit; + +import org.junit.jupiter.api.Test; +import uk.ac.ebi.eva.submission.util.HTMLHelper; + +import static org.junit.Assert.assertEquals; + +public class HTMLHelperTest { + + @Test + public void testAddLineBreak() { + String expectedHTML = "
"; + String actualHTML = new HTMLHelper().addLineBreak().build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void testAddGap() { + // adding a gap of 3 lines means you need to add 4
tags, + // one for taking the cursor to the new line and the rest for the actual gap + String expectedHTML = "



"; + String actualHTML = new HTMLHelper().addGap(3).build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void testAddText() { + String expectedHTML = "sample text"; + String actualHTML = new HTMLHelper().addText("sample text").build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void testAddTextWithSize() { + String expectedHTML = "sample text"; + String actualHTML = new HTMLHelper().addTextWithSize("sample text", 5).build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void testAddTextWithColour() { + String expectedHTML = "sample text"; + String actualHTML = new HTMLHelper().addTextWithColor("sample text", "red").build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void testAddBoldText() { + String expectedHTML = "sample text"; + String actualHTML = new HTMLHelper().addBoldText("sample text").build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void testAddLink() { + String expectedHTML = "abc"; + String actualHTML = new HTMLHelper().addLink("abc@example.com", "abc").build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void testAddEmailLink() { + String expectedHTML = "abc@example.com"; + String actualHTML = new HTMLHelper().addEmailLink("abc@example.com", "abc@example.com").build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void testAddEmailLinkWithSize() { + String expectedHTML = " abc@example.com "; + String actualHTML = new HTMLHelper().addEmailLinkWithSize("abc@example.com", "abc@example.com", 5).build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void addBoldTextWithColour() { + String expectedHTML = "sample text"; + String actualHTML = new HTMLHelper().addBoldTextWithColor("sample text", "red").build(); + assertEquals(expectedHTML, actualHTML); + } + + @Test + public void testMultiLineHTML() { + String expectedHTML = "Dear John," + + "

" + + "Here is the update for your submission: " + + "

" + + "submission id: 12345
" + + "Submission Status: UPLOADED
" + + "Result: FAILED" + + "


"; + String actualHTMl = new HTMLHelper() + .addText("Dear " + "John" + ",") + .addGap(1) + .addText("Here is the update for your submission: ") + .addGap(1) + .addText("submission id: " + 12345) + .addLineBreak() + .addText("Submission Status: " + "UPLOADED") + .addLineBreak() + .addText("Result: ") + .addBoldTextWithColor("FAILED", "red") + .addGap(2) + .build(); + + assertEquals(expectedHTML, actualHTMl); + } + +}