diff --git a/pom.xml b/pom.xml index 46a9ad1..03eda40 100644 --- a/pom.xml +++ b/pom.xml @@ -67,6 +67,10 @@ org.springframework.boot spring-boot-starter-security + + org.springframework.boot + spring-boot-starter-mail + diff --git a/src/main/java/org/otherband/Utils.java b/src/main/java/org/otherband/Utils.java index 415c83c..603c5a3 100644 --- a/src/main/java/org/otherband/Utils.java +++ b/src/main/java/org/otherband/Utils.java @@ -1,8 +1,12 @@ package org.otherband; +import org.otherband.email.VerificationLinkEmailRequest; import org.otherband.exceptions.UserInputException; +import org.otherband.letter.RecommendationLetterController; import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; public class Utils { @@ -11,4 +15,11 @@ private Utils() { public static void validateNotBlank(String field, String fieldName) { if (isBlank(field)) throw UserInputException.formatted("[%s] cannot be blank", fieldName); } + + public static String buildLetterVerificationLink(VerificationLinkEmailRequest verificationLinkEmailRequest) { + return linkTo(methodOn(RecommendationLetterController.class) + .verify(verificationLinkEmailRequest.getLetterId(), + verificationLinkEmailRequest.getTokenId(), + verificationLinkEmailRequest.getSecretToken())).withSelfRel().toString(); + } } diff --git a/src/main/java/org/otherband/email/simulation/EmailServiceSimulator.java b/src/main/java/org/otherband/email/simulation/EmailServiceSimulator.java index 3c9e78b..632eb89 100644 --- a/src/main/java/org/otherband/email/simulation/EmailServiceSimulator.java +++ b/src/main/java/org/otherband/email/simulation/EmailServiceSimulator.java @@ -1,15 +1,11 @@ package org.otherband.email.simulation; +import org.otherband.Utils; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import org.otherband.email.EmailService; import org.otherband.email.VerificationLinkEmailRequest; -import org.otherband.letter.RecommendationLetterController; - import java.util.UUID; - -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; import static org.otherband.email.simulation.SimulatedEmailsRepository.SimulatedEmail; @Component @@ -23,23 +19,17 @@ public EmailServiceSimulator(SimulatedEmailsRepository emailsRepository) { @Override public void sendLetterVerificationLink(VerificationLinkEmailRequest verificationLinkEmailRequest) { - emailsRepository.save(buildEmail(verificationLinkEmailRequest.getLetterId(), - verificationLinkEmailRequest.getTokenId(), - verificationLinkEmailRequest.getSecretToken(), - verificationLinkEmailRequest.getReceiverEmail())); + emailsRepository.save(buildEmail(verificationLinkEmailRequest)); } - private static SimulatedEmail buildEmail(String letterId, String tokenId, String secretToken, String receiverAddress) { + private static SimulatedEmail buildEmail(VerificationLinkEmailRequest verificationLinkEmailRequest) { SimulatedEmail simulatedEmail = new SimulatedEmail(); simulatedEmail.setId(UUID.randomUUID().toString()); - simulatedEmail.setEmailTitle(String.format("Verification link for recommendation letter [%s]", letterId)); - simulatedEmail.setEmailBody(buildLink(letterId, tokenId, secretToken)); - simulatedEmail.setReceiverAddress(receiverAddress); + simulatedEmail.setEmailTitle(String.format("Verification link for recommendation letter [%s]", + verificationLinkEmailRequest.getLetterId())); + simulatedEmail.setEmailBody(Utils.buildLetterVerificationLink(verificationLinkEmailRequest)); + simulatedEmail.setReceiverAddress(verificationLinkEmailRequest.getReceiverEmail()); return simulatedEmail; } - private static String buildLink(String letterId, String tokenId, String secretToken) { - return linkTo(methodOn(RecommendationLetterController.class) - .verify(letterId, tokenId, secretToken)).withSelfRel().toString(); - } } diff --git a/src/main/java/org/otherband/email/smtp/SMTPEmailService.java b/src/main/java/org/otherband/email/smtp/SMTPEmailService.java new file mode 100644 index 0000000..a51af51 --- /dev/null +++ b/src/main/java/org/otherband/email/smtp/SMTPEmailService.java @@ -0,0 +1,32 @@ +package org.otherband.email.smtp; + +import org.otherband.Utils; +import org.otherband.email.EmailService; +import org.otherband.email.VerificationLinkEmailRequest; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Service; + +@Profile("production") +@Service +public class SMTPEmailService implements EmailService { + private final String mailUserName; + private final JavaMailSender mailSender; + + public SMTPEmailService(@Value("${spring.mail.username}") String mailUserName, JavaMailSender mailSender) { + this.mailUserName = mailUserName; + this.mailSender = mailSender; + } + + @Override + public void sendLetterVerificationLink(VerificationLinkEmailRequest verificationLinkEmailRequest) { + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom(mailUserName); + message.setTo(verificationLinkEmailRequest.getReceiverEmail()); + message.setText(Utils.buildLetterVerificationLink(verificationLinkEmailRequest)); + message.setSubject("Recommendation letter verification link"); + mailSender.send(message); + } +} \ No newline at end of file diff --git a/src/main/resources/application-mail.properties b/src/main/resources/application-mail.properties new file mode 100644 index 0000000..4e99e57 --- /dev/null +++ b/src/main/resources/application-mail.properties @@ -0,0 +1,4 @@ +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.username= +spring.mail.password= diff --git a/src/test/java/org/otherband/email/smtp/SMTPEmailServiceTest.java b/src/test/java/org/otherband/email/smtp/SMTPEmailServiceTest.java new file mode 100644 index 0000000..b9ddab8 --- /dev/null +++ b/src/test/java/org/otherband/email/smtp/SMTPEmailServiceTest.java @@ -0,0 +1,49 @@ +package org.otherband.email.smtp; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.otherband.email.VerificationLinkEmailRequest; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +class SMTPEmailServiceTest { + private static final String EXPECTED_ID = "LETTER_ID"; + public static final String EXPECTED_RECEIVER_EMAIL = "email@email.com"; + public static final String TOKEN_ID = "TOKEN_ID"; + public static final String SECRET = "SECRET"; + private SMTPEmailService service; + private final static String SENDER_EMAIL = "test@email.com"; + private JavaMailSender mailSender; + + @BeforeEach + void setup() { + mailSender = mock(JavaMailSender.class); + service = new SMTPEmailService(SENDER_EMAIL, mailSender); + } + + @Test + void testSendVerificationEmail() { + VerificationLinkEmailRequest verificationLinkEmailRequest = buildRequest(); + service.sendLetterVerificationLink(verificationLinkEmailRequest); + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SimpleMailMessage.class); + verify(mailSender).send(argumentCaptor.capture()); + SimpleMailMessage sentMessage = argumentCaptor.getValue(); + assertArrayEquals(new String[]{EXPECTED_RECEIVER_EMAIL}, sentMessage.getTo()); + assertEquals("Recommendation letter verification link", sentMessage.getSubject()); + assertTrue(sentMessage.getText().contains("/api/v1/recommendation-letter/verify/LETTER_ID/TOKEN_ID/SECRET")); + } + + private static VerificationLinkEmailRequest buildRequest() { + VerificationLinkEmailRequest request = new VerificationLinkEmailRequest(); + request.setLetterId(EXPECTED_ID); + request.setTokenId(TOKEN_ID); + request.setSecretToken(SECRET); + request.setReceiverEmail(EXPECTED_RECEIVER_EMAIL); + return request; + } +} \ No newline at end of file