-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HAI-1526 Add functions to send hanke and application invitation emails
Add templates for hanke and application invitation emails. Add functionality to send these invitations in EmailSenderService. Note: It is possible for inviter name to be unknown. In these cases the emails use only the inviter email ([email protected] kutsui sinut..). Using the new email sending features will be implemented on a different upcoming pr.
- Loading branch information
Showing
8 changed files
with
394 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,10 +10,13 @@ import assertk.assertions.startsWith | |
import com.icegreen.greenmail.configuration.GreenMailConfiguration | ||
import com.icegreen.greenmail.junit5.GreenMailExtension | ||
import com.icegreen.greenmail.util.ServerSetupTest | ||
import fi.hel.haitaton.hanke.ContactType | ||
import fi.hel.haitaton.hanke.DatabaseTest | ||
import fi.hel.haitaton.hanke.application.ApplicationType | ||
import fi.hel.haitaton.hanke.firstReceivedMessage | ||
import jakarta.mail.internet.MimeMessage | ||
import jakarta.mail.internet.MimeMultipart | ||
import org.junit.jupiter.api.Nested | ||
import org.junit.jupiter.api.Test | ||
import org.junit.jupiter.api.extension.RegisterExtension | ||
import org.springframework.beans.factory.annotation.Autowired | ||
|
@@ -22,7 +25,9 @@ import org.springframework.test.context.ActiveProfiles | |
import org.testcontainers.junit.jupiter.Testcontainers | ||
|
||
private const val TEST_EMAIL = "[email protected]" | ||
private const val HAITATON_NO_REPLY = "[email protected]" | ||
private const val APPLICATION_IDENTIFIER = "JS2300001" | ||
private const val DEFAULT_INVITER_NAME = "Kalle Kutsuja" | ||
|
||
@Testcontainers | ||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) | ||
|
@@ -39,54 +44,202 @@ class EmailSenderServiceITest : DatabaseTest() { | |
|
||
@Autowired lateinit var emailSenderService: EmailSenderService | ||
|
||
@Test | ||
fun `sendJohtoselvitysCompleteEmail sends email with correct recipient`() { | ||
emailSenderService.sendJohtoselvitysCompleteEmail(TEST_EMAIL, 13L, APPLICATION_IDENTIFIER) | ||
@Nested | ||
inner class JohtoSelvitysComplete { | ||
@Test | ||
fun `sendJohtoselvitysCompleteEmail sends email with correct recipient`() { | ||
emailSenderService.sendJohtoselvitysCompleteEmail( | ||
TEST_EMAIL, | ||
13L, | ||
APPLICATION_IDENTIFIER | ||
) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.allRecipients).hasSize(1) | ||
assertThat(email.allRecipients[0].toString()).isEqualTo(TEST_EMAIL) | ||
} | ||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.allRecipients).hasSize(1) | ||
assertThat(email.allRecipients[0].toString()).isEqualTo(TEST_EMAIL) | ||
} | ||
|
||
@Test | ||
fun `sendJohtoselvitysCompleteEmail sends email with sender from properties`() { | ||
emailSenderService.sendJohtoselvitysCompleteEmail(TEST_EMAIL, 13L, APPLICATION_IDENTIFIER) | ||
@Test | ||
fun `sendJohtoselvitysCompleteEmail sends email with sender from properties`() { | ||
emailSenderService.sendJohtoselvitysCompleteEmail( | ||
TEST_EMAIL, | ||
13L, | ||
APPLICATION_IDENTIFIER | ||
) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.from).hasSize(1) | ||
assertThat(email.from[0].toString()).isEqualTo("[email protected]") | ||
} | ||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.from).hasSize(1) | ||
assertThat(email.from[0].toString()).isEqualTo(HAITATON_NO_REPLY) | ||
} | ||
|
||
@Test | ||
fun `sendJohtoselvitysCompleteEmail sends email with correct subject`() { | ||
emailSenderService.sendJohtoselvitysCompleteEmail(TEST_EMAIL, 13L, APPLICATION_IDENTIFIER) | ||
@Test | ||
fun `sendJohtoselvitysCompleteEmail sends email with correct subject`() { | ||
emailSenderService.sendJohtoselvitysCompleteEmail( | ||
TEST_EMAIL, | ||
13L, | ||
APPLICATION_IDENTIFIER | ||
) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.subject) | ||
.isEqualTo( | ||
"Johtoselvitys JS2300001 / Ledningsutredning JS2300001 / Cable report JS2300001" | ||
) | ||
} | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.subject) | ||
.isEqualTo( | ||
"Johtoselvitys JS2300001 / Ledningsutredning JS2300001 / Cable report JS2300001" | ||
@Test | ||
fun `sendJohtoselvitysCompleteEmail sends email with parametrized hybrid body`() { | ||
emailSenderService.sendJohtoselvitysCompleteEmail( | ||
TEST_EMAIL, | ||
13L, | ||
APPLICATION_IDENTIFIER | ||
) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
val (textBody, htmlBody) = getBodiesFromHybridEmail(email) | ||
assertThat(textBody).all { | ||
contains(APPLICATION_IDENTIFIER) | ||
contains("http://localhost:3001/fi/hakemus/13") | ||
contains("http://localhost:3001/sv/ansokan/13") | ||
contains("http://localhost:3001/en/application/13") | ||
} | ||
// Compress all whitespace into single spaces so that they don't interfere with | ||
// matching. | ||
val squashedHtmlBody = htmlBody.replace("\\s+".toRegex(), " ") | ||
assertThat(squashedHtmlBody).all { | ||
contains(APPLICATION_IDENTIFIER) | ||
contains("""<a href="http://localhost:3001/fi/hakemus/13">""") | ||
contains("""<a href="http://localhost:3001/sv/ansokan/13">""") | ||
contains("""<a href="http://localhost:3001/en/application/13">""") | ||
} | ||
} | ||
} | ||
|
||
@Test | ||
fun `sendJohtoselvitysCompleteEmail sends email with parametrized hybrid body`() { | ||
emailSenderService.sendJohtoselvitysCompleteEmail(TEST_EMAIL, 13L, APPLICATION_IDENTIFIER) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
val (textBody, htmlBody) = getBodiesFromHybridEmail(email) | ||
assertThat(textBody).all { | ||
contains(APPLICATION_IDENTIFIER) | ||
contains("http://localhost:3001/fi/hakemus/13") | ||
contains("http://localhost:3001/sv/ansokan/13") | ||
contains("http://localhost:3001/en/application/13") | ||
@Nested | ||
inner class HankeInvitation { | ||
|
||
@Test | ||
fun `sendHankeInvitationEmail sends email with correct recipient`() { | ||
emailSenderService.sendHankeInvitationEmail(hankeInvitationData()) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.allRecipients).hasSize(1) | ||
assertThat(email.allRecipients[0].toString()).isEqualTo(TEST_EMAIL) | ||
} | ||
|
||
@Test | ||
fun `sendHankeInvitationEmail sends email with sender from properties`() { | ||
emailSenderService.sendHankeInvitationEmail(hankeInvitationData()) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.from).hasSize(1) | ||
assertThat(email.from[0].toString()).isEqualTo(HAITATON_NO_REPLY) | ||
} | ||
|
||
@Test | ||
fun `sendHankeInvitationEmail sends email with correct subject`() { | ||
emailSenderService.sendHankeInvitationEmail(hankeInvitationData()) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.subject).isEqualTo("Sinut on lisätty hankkeelle HAI24-1") | ||
} | ||
// Compress all whitespace into single spaces so that they don't interfere with matching. | ||
val squashedHtmlBody = htmlBody.replace("\\s+".toRegex(), " ") | ||
assertThat(squashedHtmlBody).all { | ||
contains(APPLICATION_IDENTIFIER) | ||
contains("""<a href="http://localhost:3001/fi/hakemus/13">""") | ||
contains("""<a href="http://localhost:3001/sv/ansokan/13">""") | ||
contains("""<a href="http://localhost:3001/en/application/13">""") | ||
|
||
@Test | ||
fun `sendHankeInvitationEmail sends email with parametrized hybrid body`() { | ||
val data = hankeInvitationData() | ||
|
||
emailSenderService.sendHankeInvitationEmail(data) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
val (textBody, htmlBody) = getBodiesFromHybridEmail(email) | ||
assertThat(textBody).all { | ||
startsWith("${data.inviterName} (${data.inviterEmail}) lisäsi sinut") | ||
contains("hankkeelle ${data.hankeNimi} (${data.hankeTunnus}).") | ||
contains("http://localhost:3001/${data.invitationToken}") | ||
} | ||
assertThat(htmlBody).all { | ||
contains("<p>${data.inviterName} (${data.inviterEmail}) lisäsi sinut") | ||
contains("hankkeelle <b>${data.hankeNimi} (${data.hankeTunnus})</b>.") | ||
contains("""<a href="http://localhost:3001/${data.invitationToken}">""") | ||
} | ||
} | ||
|
||
@Test | ||
fun `sendHankeInvitationEmail handles input without inviter name`() { | ||
val data = hankeInvitationData(inviterName = null) | ||
|
||
emailSenderService.sendHankeInvitationEmail(data) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
val (textBody, htmlBody) = getBodiesFromHybridEmail(email) | ||
assertThat(textBody).startsWith("Asioija ${data.inviterEmail} lisäsi sinut") | ||
assertThat(htmlBody).contains("<p>Asioija ${data.inviterEmail} lisäsi sinut") | ||
} | ||
} | ||
|
||
@Nested | ||
inner class ApplicationInvitation { | ||
@Test | ||
fun `sendApplicationInvitationEmail sends email with correct recipient`() { | ||
emailSenderService.sendApplicationInvitationEmail(applicationInvitationData()) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.allRecipients).hasSize(1) | ||
assertThat(email.allRecipients[0].toString()).isEqualTo(TEST_EMAIL) | ||
} | ||
|
||
@Test | ||
fun `sendApplicationInvitationEmail sends email with sender from properties`() { | ||
emailSenderService.sendApplicationInvitationEmail(applicationInvitationData()) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.from).hasSize(1) | ||
assertThat(email.from[0].toString()).isEqualTo(HAITATON_NO_REPLY) | ||
} | ||
|
||
@Test | ||
fun `sendApplicationInvitationEmail sends email with correct subject`() { | ||
val data = applicationInvitationData() | ||
emailSenderService.sendApplicationInvitationEmail(data) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
assertThat(email.subject) | ||
.isEqualTo("Sinut on lisätty hakemukselle ${data.applicationIdentifier}") | ||
} | ||
|
||
@Test | ||
fun `sendApplicationInvitationEmail sends email with parametrized hybrid body`() { | ||
val data = applicationInvitationData() | ||
|
||
emailSenderService.sendApplicationInvitationEmail(data) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
val (textBody, htmlBody) = getBodiesFromHybridEmail(email) | ||
assertThat(textBody).all { | ||
startsWith("${data.inviterName} (${data.inviterEmail}) on") | ||
contains("tehnyt johtoselvityshakemuksen (${data.applicationIdentifier})") | ||
contains("hankkeella ${data.hankeTunnus}") | ||
contains("rooliin ${data.roleType.text()}.") | ||
contains("Tarkastele hakemusta Haitattomassa: http://localhost:3001") | ||
} | ||
assertThat(htmlBody).all { | ||
contains("${data.inviterName} (${data.inviterEmail})") | ||
contains("johtoselvityshakemuksen (${data.applicationIdentifier})") | ||
contains("rooliin ${data.roleType.text()}") | ||
contains("""Tarkastele hakemusta Haitattomassa: <a href="http://localhost:3001">""") | ||
} | ||
} | ||
|
||
@Test | ||
fun `sendApplicationInvitationEmail handles input without inviter name`() { | ||
val data = applicationInvitationData(inviterName = null) | ||
|
||
emailSenderService.sendApplicationInvitationEmail(data) | ||
|
||
val email = greenMail.firstReceivedMessage() | ||
val (textBody, htmlBody) = getBodiesFromHybridEmail(email) | ||
assertThat(textBody).startsWith("Asioija ${data.inviterEmail} on tehnyt") | ||
assertThat(htmlBody).contains("<p>Asioija ${data.inviterEmail} on tehnyt") | ||
} | ||
} | ||
|
||
|
@@ -116,4 +269,27 @@ class EmailSenderServiceITest : DatabaseTest() { | |
.map { i -> mp3.getBodyPart(i).content.toString() } | ||
return Pair(bodies[0], bodies[1]) | ||
} | ||
|
||
private fun hankeInvitationData(inviterName: String? = DEFAULT_INVITER_NAME) = | ||
HankeInvitationData( | ||
inviterName = inviterName, | ||
inviterEmail = "[email protected]", | ||
recipientEmail = TEST_EMAIL, | ||
hankeTunnus = "HAI24-1", | ||
hankeNimi = "Mannerheimintien liikenneuudistus", | ||
invitationToken = "MgtzRbcPsvoKQamnaSxCnmW7", | ||
) | ||
|
||
private fun applicationInvitationData(inviterName: String? = DEFAULT_INVITER_NAME) = | ||
ApplicationInvitationData( | ||
inviterName = inviterName, | ||
inviterEmail = "[email protected]", | ||
recipientEmail = TEST_EMAIL, | ||
applicationType = ApplicationType.CABLE_REPORT, | ||
applicationIdentifier = APPLICATION_IDENTIFIER, | ||
hankeTunnus = "HAI24-1", | ||
roleType = ContactType.RAKENNUTTAJA, | ||
) | ||
|
||
private fun ContactType.text() = toString().lowercase() | ||
} |
Oops, something went wrong.