Skip to content

Commit

Permalink
PIN-3910 Extended Mail ADT (#281)
Browse files Browse the repository at this point in the history
  • Loading branch information
nttdata-rtorsoli authored Sep 28, 2023
1 parent cba7986 commit 19bb619
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,40 +1,56 @@
package it.pagopa.interop.commons.mail

import spray.json.{DefaultJsonProtocol, RootJsonFormat}
import spray.json._
import io.circe._
import io.circe.generic.semiauto._
import javax.mail.internet.InternetAddress
import it.pagopa.interop.commons.utils.SprayCommonFormats.uuidFormat
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import org.typelevel.literally.Literally
import scala.util.Try
import courier._
import java.util.UUID

sealed trait Mail {
val id: UUID
val recipients: Seq[InternetAddress]
val subject: String

def renderContent: Content = this match {
case TextMail(_, _, body, Nil) => Text(body)
case TextMail(_, _, body, as) =>
case TextMail(_, _, _, body, Nil) => Text(body)
case TextMail(_, _, _, body, as) =>
as.foldLeft(Multipart().text(body)) { (c, a) => c.attachBytes(a.bytes, a.name, a.mimeType) }
case HttpMail(_, _, body, as) =>
case HttpMail(_, _, _, body, as) =>
as.foldLeft(Multipart().html(body)) { (c, a) => c.attachBytes(a.bytes, a.name, a.mimeType) }
}
}

final case class TextMail(
id: UUID = UUID.randomUUID(),
recipients: Seq[InternetAddress],
subject: String,
body: String,
attachments: Seq[MailAttachment] = Seq.empty
) extends Mail

final case class HttpMail(
id: UUID = UUID.randomUUID(),
recipients: Seq[InternetAddress],
subject: String,
body: String,
attachments: Seq[MailAttachment] = Seq.empty
) extends Mail

final case class MailAttachment(name: String, bytes: Array[Byte], mimeType: String)
final case class MailAttachment(name: String, bytes: Array[Byte], mimeType: String) {
override def equals(obj: Any): Boolean = obj match {
case MailAttachment(n, b, m) => name == n && m == mimeType && bytes.sameElements(b)
case _ => false
}
}

object Mail extends SprayJsonSupport with DefaultJsonProtocol {

object Mail {
private object MailLiteral extends Literally[InternetAddress] {
def validate(c: Context)(s: String): Either[String, c.Expr[InternetAddress]] = {
import c.universe.{Try => _, _}
Expand Down Expand Up @@ -62,4 +78,32 @@ object Mail {
implicit class MailSyntax(val sc: StringContext) extends AnyVal {
def mail(args: Any*): InternetAddress = macro MailLiteral.make
}

implicit val encodeInternetAddress: Encoder[InternetAddress] =
Encoder.encodeString.contramap[InternetAddress](_.getAddress())

implicit val decodeInstant: Decoder[InternetAddress] = Decoder.decodeString.emapTry { str =>
Try(new InternetAddress(str))
}

implicit val mailAttachmentEncoder: Encoder[MailAttachment] = deriveEncoder
implicit val mailAttachmentDecoder: Decoder[MailAttachment] = deriveDecoder

implicit val textMailEncoder: Encoder[TextMail] = deriveEncoder
implicit val textMailDecoder: Decoder[TextMail] = deriveDecoder

implicit val httpMailEncoder: Encoder[HttpMail] = deriveEncoder
implicit val httpMailDecoder: Decoder[HttpMail] = deriveDecoder

implicit val mailAttachmentFormat: RootJsonFormat[MailAttachment] = jsonFormat3(MailAttachment)

implicit object InternetAddressFormat extends JsonFormat[InternetAddress] {
def write(ia: InternetAddress) = JsString(s"${ia.getAddress()}")
def read(json: JsValue) = json match {
case JsString(address) => new InternetAddress(address)
case _ => deserializationError("JString type expected")
}
}
implicit val textMailFormat: RootJsonFormat[TextMail] = jsonFormat5(TextMail)
implicit val httpMailFormat: RootJsonFormat[HttpMail] = jsonFormat5(HttpMail)
}
10 changes: 7 additions & 3 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ object Dependencies {

private[this] object circe {
lazy val namespace = "io.circe"
lazy val yaml = namespace %% "circe-yaml" % circeVersion
lazy val core = namespace %% "circe-core" % circeVersion
lazy val parser = namespace %% "circe-parser" % circeVersion
lazy val yaml = namespace %% "circe-yaml" % circeVersion
lazy val core = namespace %% "circe-core" % circeVersion
lazy val generic = namespace %% "circe-generic" % circeVersion
lazy val parser = namespace %% "circe-parser" % circeVersion
}

private[this] object commons {
Expand Down Expand Up @@ -167,6 +168,9 @@ object Dependencies {
courier.mail % Compile,
"org.typelevel" %% "literally" % "1.1.0" % Compile,
"com.github.pureconfig" %% "pureconfig" % "0.17.2" % Compile,
circe.core % Compile,
circe.generic % Compile,
circe.parser % Compile,
courier.testMocking % Test
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ trait AkkaResponses {
): StandardRoute =
complete(statusCode.intValue, headers, Problem(statusCode, error, serviceCode, getCorrelationId(contexts)))

private def completeWithErrors(
statusCode: StatusCode,
headers: List[HttpHeader],
errors: List[ComponentError]
)(implicit contexts: Seq[(String, String)], serviceCode: ServiceCode): StandardRoute =
private def completeWithErrors(statusCode: StatusCode, headers: List[HttpHeader], errors: List[ComponentError])(
implicit
contexts: Seq[(String, String)],
serviceCode: ServiceCode
): StandardRoute =
complete(statusCode.intValue, headers, Problem(statusCode, errors, serviceCode, getCorrelationId(contexts)))

@inline private def getCorrelationId(contexts: Seq[(String, String)]): Option[String] =
Expand Down

0 comments on commit 19bb619

Please sign in to comment.