diff --git a/integraatio/src/test/scala/fi/oph/viestinvalitys/IntegraatioTest.scala b/integraatio/src/test/scala/fi/oph/viestinvalitys/IntegraatioTest.scala
index 260ed2cf..b075ad05 100644
--- a/integraatio/src/test/scala/fi/oph/viestinvalitys/IntegraatioTest.scala
+++ b/integraatio/src/test/scala/fi/oph/viestinvalitys/IntegraatioTest.scala
@@ -6,7 +6,8 @@ import com.fasterxml.jackson.datatype.jdk8.Jdk8Module
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.nimbusds.jose.util.StandardCharset
-import fi.oph.viestinvalitys.business.{Kieli, Kontakti, Lahetys, Liite, LiitteenTila, Prioriteetti, SisallonTyyppi, VastaanottajanTila, Viesti}
+import fi.oph.viestinvalitys.business.{Kieli, Kontakti, Lahetys, Liite, LiitteenTila, Prioriteetti, SisallonTyyppi, VastaanottajanSiirtyma, VastaanottajanTila, Viesti}
+import fi.oph.viestinvalitys.lahetys.LambdaHandler.SAHKOPOSTIOSOITE_EI_VALIDI_ERROR
import fi.oph.viestinvalitys.security.{AuditLog, AuditOperation}
import fi.oph.viestinvalitys.util.AwsUtil
import fi.oph.viestinvalitys.vastaanotto.model.Lahetys.Lahettaja
@@ -767,4 +768,29 @@ class IntegraatioTest extends BaseIntegraatioTesti {
}, 60.seconds)
catch
case e: Exception => Assertions.fail("Vastaanottaja ei muuttunut delivery-tilaan sallitussa ajassa")
+
+ /**
+ * Testataan virheellisen vastaanottajan (sähköposti ei validi) lähetys. Pitää mennä virhetilaan.
+ */
+ @Test def testLuoViestiVirheellinenVastaanottaja(): Unit =
+ // luodaan viesti
+ val luoViestiResult = mvc.perform(jsonPost(LahetysAPIConstants.LUO_VIESTI_PATH, getViesti(vastaanottajat =
+ java.util.List.of(VastaanottajaImpl(Optional.empty(), Optional.of("täysin väärä osoite")))))
+ .`with`(user("kayttaja").roles(SecurityConstants.SECURITY_ROOLI_LAHETYS_FULL.replace("ROLE_", ""))))
+ .andExpect(status().isOk()).andReturn()
+ val response = objectMapper.readValue(luoViestiResult.getResponse.getContentAsString, classOf[LuoViestiSuccessResponseImpl])
+ val vastaanottaja = kantaOperaatiot.getLahetyksenVastaanottajat(response.lahetysTunniste, Option.empty, Option.empty).head
+
+ // haetaan viestin ainoan vastaanottajan tila sekunnin välein kunnes tilassa VIRHE
+ var siirtyma: VastaanottajanSiirtyma = null
+ try
+ Await.ready(Future {
+ while (siirtyma==null || !VastaanottajanTila.VIRHE.equals(siirtyma.tila))
+ Thread.sleep(1000)
+ siirtyma = kantaOperaatiot.getVastaanottajanSiirtymat(vastaanottaja.tunniste).head
+ }, 60.seconds)
+ catch
+ case e: Exception => Assertions.fail("Vastaanottaja ei muuttunut delivery-tilaan sallitussa ajassa")
+
+ Assertions.assertEquals(SAHKOPOSTIOSOITE_EI_VALIDI_ERROR, siirtyma.lisatiedot)
}
diff --git a/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Lahetys.scala b/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Lahetys.scala
index 8f200b57..5b881266 100644
--- a/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Lahetys.scala
+++ b/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Lahetys.scala
@@ -21,7 +21,7 @@ case class LahettajaImpl(
@(Schema @field)(example = "Opintopolku", maxLength = Viesti.VIESTI_NIMI_MAX_PITUUS)
@BeanProperty nimi: Optional[String],
- @(Schema @field)(description="Domainin pitää olla opintopolku.fi", example = "noreply@opintopolku.fi", requiredMode=RequiredMode.REQUIRED)
+ @(Schema @field)(description="Domainin pitää olla opintopolku.fi", example = "noreply@opintopolku.fi", requiredMode=RequiredMode.REQUIRED, maxLength = Viesti.VIESTI_OSOITE_MAX_PITUUS)
@BeanProperty sahkopostiOsoite: Optional[String],
) extends Lahettaja {
diff --git a/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Viesti.java b/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Viesti.java
index 8285d1f1..7e2d1135 100644
--- a/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Viesti.java
+++ b/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Viesti.java
@@ -33,6 +33,7 @@ public interface Viesti {
* Viestin lähettäjän ja yksittäisten vastaanottajien nimien maksimipituus.
*/
static final int VIESTI_NIMI_MAX_PITUUS = 64;
+ static final int VIESTI_OSOITE_MAX_PITUUS = 512;
static final int VIESTI_SALAISUUS_MIN_PITUUS = 8;
static final int VIESTI_SALAISUUS_MAX_PITUUS = 1024;
diff --git a/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Viesti.scala b/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Viesti.scala
index b4b7bbcb..6efd6e87 100644
--- a/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Viesti.scala
+++ b/lahetysrajapinta/src/main/scala/fi/oph/viestinvalitys/vastaanotto/model/Viesti.scala
@@ -26,7 +26,7 @@ case class VastaanottajaImpl(
@(Schema @field)(example = "Vallu Vastaanottaja", maxLength = Viesti.VIESTI_NIMI_MAX_PITUUS)
@BeanProperty nimi: Optional[String],
- @(Schema @field)(example = "vallu.vastaanottaja@example.com", requiredMode=RequiredMode.REQUIRED)
+ @(Schema @field)(example = "vallu.vastaanottaja@example.com", requiredMode=RequiredMode.REQUIRED, maxLength = Viesti.VIESTI_OSOITE_MAX_PITUUS)
@BeanProperty sahkopostiOsoite: Optional[String],
) extends Vastaanottaja {
diff --git a/lambdat/lahetys/pom.xml b/lambdat/lahetys/pom.xml
index a3f797c5..363202c6 100644
--- a/lambdat/lahetys/pom.xml
+++ b/lambdat/lahetys/pom.xml
@@ -58,6 +58,10 @@
net.logstash.logback
logstash-logback-encoder
+
+ commons-validator
+ commons-validator
+
diff --git a/lambdat/lahetys/src/main/scala/fi/oph/viestinvalitys/lahetys/LambdaHandler.scala b/lambdat/lahetys/src/main/scala/fi/oph/viestinvalitys/lahetys/LambdaHandler.scala
index e02da5f9..727e5093 100644
--- a/lambdat/lahetys/src/main/scala/fi/oph/viestinvalitys/lahetys/LambdaHandler.scala
+++ b/lambdat/lahetys/src/main/scala/fi/oph/viestinvalitys/lahetys/LambdaHandler.scala
@@ -20,6 +20,7 @@ import software.amazon.awssdk.core.SdkBytes
import software.amazon.awssdk.services.cloudwatch.model.{Dimension, MetricDatum, PutMetricDataRequest, StandardUnit}
import software.amazon.awssdk.services.s3.model.GetObjectRequest
import software.amazon.awssdk.services.ses.model.{RawMessage, SendRawEmailRequest}
+import org.apache.commons.validator.routines.EmailValidator
import java.io.ByteArrayOutputStream
import java.time.Instant
@@ -28,6 +29,8 @@ import java.util.UUID
import scala.jdk.CollectionConverters.{CollectionHasAsScala, SeqHasAsJava}
object LambdaHandler {
+ val SAHKOPOSTIOSOITE_EI_VALIDI_ERROR = "Sähköpostiosoite ei validi"
+
val LOG = LoggerFactory.getLogger(classOf[LambdaHandler]);
val queueUrl = ConfigurationUtil.getConfigurationItem(ConfigurationUtil.AJASTUS_QUEUE_URL_KEY).get;
val kantaOperaatiot = new KantaOperaatiot(DbUtil.database)
@@ -97,60 +100,70 @@ class LambdaHandler extends RequestHandler[SQSEvent, Void], Resource {
LogContext(vastaanottajaTunniste = vastaanottaja.tunniste.toString, viestiTunniste = vastaanottaja.viestiTunniste.toString)(() => {
try {
LOG.info(s"Lähetetään viestiä vastaanottajalle ${vastaanottaja.tunniste.toString}")
- val viesti = viestit.getOrElseUpdate(vastaanottaja.viestiTunniste, kantaOperaatiot.getViestit(Seq(vastaanottaja.viestiTunniste)).find(v => true).get)
-
- var builder = EmailBuilder.startingBlank()
- .withContentTransferEncoding(ContentTransferEncoding.BASE_64)
- .withSubject(viesti.otsikko)
-
- if (viesti.replyTo.isDefined)
- builder.withReplyTo(viesti.replyTo.get)
-
- viesti.sisallonTyyppi match {
- case SisallonTyyppi.TEXT => builder = builder.withPlainText(viesti.sisalto)
- case SisallonTyyppi.HTML => builder = builder.withHTMLText(viesti.sisalto)
- }
-
- liitteet.getOrElseUpdate(viesti.tunniste, kantaOperaatiot.getViestinLiitteet(Seq(viesti.tunniste))
- .find((viestiTunniste, liitteet) => true).map((viestiTunniste, liitteet) => liitteet.map(liite => {
- val getObjectResponse = AwsUtil.s3Client.getObject(GetObjectRequest
- .builder()
- .bucket(bucketName)
- .key(liite.tunniste.toString)
+
+ if(!EmailValidator.getInstance().isValid(vastaanottaja.kontakti.sahkoposti))
+ LOG.error(s"Vastaanottajan ${vastaanottaja.tunniste.toString} sähköposti ei ole validi, siirretään suoraan virhetilaan")
+ val changes: Changes = new Changes.Builder()
+ .added("lisatiedot", SAHKOPOSTIOSOITE_EI_VALIDI_ERROR)
+ .updated("vastaanottajanTila", vastaanottaja.tila.toString, VastaanottajanTila.VIRHE.toString)
+ .build()
+ AuditLog.logChanges(AuditLog.getAuditUserForLambda(), Map("vastaanottaja" -> vastaanottaja.tunniste.toString), AuditOperation.UpdateVastaanottajanTila, changes)
+ kantaOperaatiot.paivitaVastaanottajaVirhetilaan(vastaanottaja.tunniste, SAHKOPOSTIOSOITE_EI_VALIDI_ERROR)
+ else
+ val viesti = viestit.getOrElseUpdate(vastaanottaja.viestiTunniste, kantaOperaatiot.getViestit(Seq(vastaanottaja.viestiTunniste)).find(v => true).get)
+
+ var builder = EmailBuilder.startingBlank()
+ .withContentTransferEncoding(ContentTransferEncoding.BASE_64)
+ .withSubject(viesti.otsikko)
+
+ if (viesti.replyTo.isDefined)
+ builder.withReplyTo(viesti.replyTo.get)
+
+ viesti.sisallonTyyppi match {
+ case SisallonTyyppi.TEXT => builder = builder.withPlainText(viesti.sisalto)
+ case SisallonTyyppi.HTML => builder = builder.withHTMLText(viesti.sisalto)
+ }
+
+ liitteet.getOrElseUpdate(viesti.tunniste, kantaOperaatiot.getViestinLiitteet(Seq(viesti.tunniste))
+ .find((viestiTunniste, liitteet) => true).map((viestiTunniste, liitteet) => liitteet.map(liite => {
+ val getObjectResponse = AwsUtil.s3Client.getObject(GetObjectRequest
+ .builder()
+ .bucket(bucketName)
+ .key(liite.tunniste.toString)
+ .build())
+ (liite, getObjectResponse.readAllBytes)
+ })).getOrElse(Seq.empty)).foreach((liite, bytes) => {
+ builder = builder.withAttachment(liite.nimi, bytes, liite.contentType)
+ })
+
+ val sesTunniste = {
+ if (mode == Mode.PRODUCTION)
+ this.sendSesEmail(builder
+ .from(viesti.lahettaja.nimi.getOrElse(null), viesti.lahettaja.sahkoposti)
+ .to(vastaanottaja.kontakti.nimi.getOrElse(null), vastaanottaja.kontakti.sahkoposti)
+ .buildEmail())
+ else
+ sendTestEmail(vastaanottaja, builder.from(viesti.lahettaja.nimi.getOrElse(null), s"noreply@${ConfigurationUtil.opintopolkuDomain}"))
+ }
+ val changes: Changes = new Changes.Builder()
+ .added("sesTunniste", sesTunniste)
+ .updated("vastaanottajanTila",vastaanottaja.tila.toString, VastaanottajanTila.LAHETETTY.toString)
+ .build()
+ AuditLog.logChanges(AuditLog.getAuditUserForLambda(), Map("vastaanottaja" -> vastaanottaja.tunniste.toString), AuditOperation.SendEmail, changes)
+ LOG.info(s"Lähetetty viesti vastaanottajalle ${vastaanottaja.tunniste.toString}")
+ kantaOperaatiot.paivitaVastaanottajaLahetetyksi(vastaanottaja.tunniste, sesTunniste)
+
+ metricDatums.add(MetricDatum.builder()
+ .metricName("LahetyksienMaara")
+ .value(1)
+ .storageResolution(1)
+ .dimensions(Seq(Dimension.builder()
+ .name("Prioriteetti")
+ .value(viesti.prioriteetti.toString)
+ .build()).asJava)
+ .timestamp(Instant.now())
+ .unit(StandardUnit.COUNT)
.build())
- (liite, getObjectResponse.readAllBytes)
- })).getOrElse(Seq.empty)).foreach((liite, bytes) => {
- builder = builder.withAttachment(liite.nimi, bytes, liite.contentType)
- })
-
- val sesTunniste = {
- if (mode == Mode.PRODUCTION)
- this.sendSesEmail(builder
- .from(viesti.lahettaja.nimi.getOrElse(null), viesti.lahettaja.sahkoposti)
- .to(vastaanottaja.kontakti.nimi.getOrElse(null), vastaanottaja.kontakti.sahkoposti)
- .buildEmail())
- else
- sendTestEmail(vastaanottaja, builder.from(viesti.lahettaja.nimi.getOrElse(null), s"noreply@${ConfigurationUtil.opintopolkuDomain}"))
- }
- val changes: Changes = new Changes.Builder()
- .added("sesTunniste", sesTunniste)
- .updated("vastaanottajanTila",vastaanottaja.tila.toString, VastaanottajanTila.LAHETETTY.toString)
- .build()
- AuditLog.logChanges(AuditLog.getAuditUserForLambda(), Map("vastaanottaja" -> vastaanottaja.tunniste.toString), AuditOperation.SendEmail, changes)
- LOG.info(s"Lähetetty viesti vastaanottajalle ${vastaanottaja.tunniste.toString}")
- kantaOperaatiot.paivitaVastaanottajaLahetetyksi(vastaanottaja.tunniste, sesTunniste)
-
- metricDatums.add(MetricDatum.builder()
- .metricName("LahetyksienMaara")
- .value(1)
- .storageResolution(1)
- .dimensions(Seq(Dimension.builder()
- .name("Prioriteetti")
- .value(viesti.prioriteetti.toString)
- .build()).asJava)
- .timestamp(Instant.now())
- .unit(StandardUnit.COUNT)
- .build())
} catch {
case e: Exception =>
LOG.error(s"Virhe lähetettäessä viestiä vastaanottajalle ${vastaanottaja.tunniste.toString}", e)
diff --git a/lambdat/vastaanotto/src/main/scala/fi/oph/viestinvalitys/vastaanotto/validation/ViestiValidator.scala b/lambdat/vastaanotto/src/main/scala/fi/oph/viestinvalitys/vastaanotto/validation/ViestiValidator.scala
index 9403681e..b02e48d1 100644
--- a/lambdat/vastaanotto/src/main/scala/fi/oph/viestinvalitys/vastaanotto/validation/ViestiValidator.scala
+++ b/lambdat/vastaanotto/src/main/scala/fi/oph/viestinvalitys/vastaanotto/validation/ViestiValidator.scala
@@ -4,7 +4,6 @@ import fi.oph.viestinvalitys.vastaanotto.model.Lahetys.*
import fi.oph.viestinvalitys.vastaanotto.model.LahetysImpl.LAHETYS_PRIORITEETTI_KORKEA
import fi.oph.viestinvalitys.vastaanotto.model.Viesti.*
import fi.oph.viestinvalitys.vastaanotto.validation.LahetysValidator
-import org.apache.commons.validator.routines.EmailValidator
import java.util.stream.Collectors
import java.util.{List, Optional, UUID}
@@ -52,7 +51,7 @@ object ViestiValidator:
final val VALIDATION_VASTAANOTTAJA_OSOITE_DUPLICATE = "vastaanottajat: Osoite-kentissä on duplikaatteja: "
final val VALIDATION_VASTAANOTTAJAN_NIMI_LIIAN_PITKA = "nimi-kenttä voi maksimissaan olla " + VIESTI_NIMI_MAX_PITUUS + " merkkiä pitkä"
final val VALIDATION_VASTAANOTTAJAN_OSOITE_TYHJA = "sähköpostiosoite-kenttä on pakollinen"
- final val VALIDATION_VASTAANOTTAJAN_OSOITE_INVALID = "sähköpostiosoite ei ole validi sähköpostiosoite"
+ final val VALIDATION_VASTAANOTTAJAN_OSOITE_LIIAN_PITKA = "sähköpostiosoite void maksimissaan olla " + " merkkiä pitkä"
final val VALIDATION_LIITETUNNISTE_NULL = "liiteTunnisteet: Kenttä sisältää null-arvoja"
final val VALIDATION_LIITETUNNISTE_LIIKAA = "liiteTunnisteet: Viestillä voi maksimissaan olla " + VIESTI_LIITTEET_MAX_MAARA + " liitettä"
@@ -214,8 +213,8 @@ object ViestiValidator:
// validoidaan sahkopostiosoite
if (vastaanottaja.getSahkopostiOsoite.isEmpty || vastaanottaja.getSahkopostiOsoite.get.length == 0)
vastaanottajaVirheet.incl(VALIDATION_VASTAANOTTAJAN_OSOITE_TYHJA)
- else if (!EmailValidator.getInstance().isValid(vastaanottaja.getSahkopostiOsoite.get))
- vastaanottajaVirheet.incl(VALIDATION_VASTAANOTTAJAN_OSOITE_INVALID)
+ else if (vastaanottaja.getSahkopostiOsoite.get().length>Viesti.VIESTI_OSOITE_MAX_PITUUS)
+ vastaanottajaVirheet.incl(VALIDATION_VASTAANOTTAJAN_OSOITE_LIIAN_PITKA)
else vastaanottajaVirheet).get
if (!vastaanottajaVirheet.isEmpty)
diff --git a/lambdat/vastaanotto/src/test/scala/fi/oph/viestinvalitys/vastaanotto/validation/ViestiValidatorTest.scala b/lambdat/vastaanotto/src/test/scala/fi/oph/viestinvalitys/vastaanotto/validation/ViestiValidatorTest.scala
index f8e77e80..80d0bf53 100644
--- a/lambdat/vastaanotto/src/test/scala/fi/oph/viestinvalitys/vastaanotto/validation/ViestiValidatorTest.scala
+++ b/lambdat/vastaanotto/src/test/scala/fi/oph/viestinvalitys/vastaanotto/validation/ViestiValidatorTest.scala
@@ -176,17 +176,17 @@ class ViestiValidatorTest {
Assertions.assertEquals(Set("Vastaanottaja (nimi: Vallu Vastaanottaja, sähköpostiosoite: Optional.empty): " + ViestiValidator.VALIDATION_VASTAANOTTAJAN_OSOITE_TYHJA),
ViestiValidator.validateVastaanottajat(Optional.of(util.List.of(getVastaanottaja("Vallu Vastaanottaja", null)))))
- // ei validi sähköpostiosoite ei ole sallittu
- Assertions.assertEquals(Set("Vastaanottaja (nimi: Vallu Vastaanottaja, sähköpostiosoite: Optional[ei validi osoite]): " + ViestiValidator.VALIDATION_VASTAANOTTAJAN_OSOITE_INVALID),
- ViestiValidator.validateVastaanottajat(Optional.of(util.List.of(getVastaanottaja("Vallu Vastaanottaja", "ei validi osoite")))))
+ // liian pitkä sähköpostiosoite ei ole sallittu
+ Assertions.assertEquals(Set("Vastaanottaja (nimi: Vallu Vastaanottaja, sähköpostiosoite: Optional[" + "x".repeat(Viesti.VIESTI_OSOITE_MAX_PITUUS+1) + "]): " + ViestiValidator.VALIDATION_VASTAANOTTAJAN_OSOITE_LIIAN_PITKA),
+ ViestiValidator.validateVastaanottajat(Optional.of(util.List.of(getVastaanottaja("Vallu Vastaanottaja", "x".repeat(Viesti.VIESTI_OSOITE_MAX_PITUUS+1))))))
// kaikki virheet kerätään
Assertions.assertEquals(Set(
"Vastaanottaja (nimi: Vallu Vastaanottaja, sähköpostiosoite: Optional.empty): " + ViestiValidator.VALIDATION_VASTAANOTTAJAN_OSOITE_TYHJA,
- "Vastaanottaja (nimi: Vallu Vastaanottaja, sähköpostiosoite: Optional[ei validi osoite]): " + ViestiValidator.VALIDATION_VASTAANOTTAJAN_OSOITE_INVALID),
+ "Vastaanottaja (nimi: Vallu Vastaanottaja, sähköpostiosoite: Optional[" + "x".repeat(Viesti.VIESTI_OSOITE_MAX_PITUUS+1) + "]): " + ViestiValidator.VALIDATION_VASTAANOTTAJAN_OSOITE_LIIAN_PITKA),
ViestiValidator.validateVastaanottajat(Optional.of(util.List.of(
getVastaanottaja("Vallu Vastaanottaja", null),
- getVastaanottaja("Vallu Vastaanottaja", "ei validi osoite")
+ getVastaanottaja("Vallu Vastaanottaja", "x".repeat(Viesti.VIESTI_OSOITE_MAX_PITUUS+1))
))))
// duplikaattiosoitteet eivät ole sallittuja