backend/app/model/frontend/email/EmailThread.scala (45 lines of code) (raw):

package model.frontend.email import java.time.OffsetDateTime import org.neo4j.driver.v1.Value import utils.attempt.Attempt import model._ import play.api.libs.json.Json import scala.jdk.CollectionConverters._ import scala.concurrent.ExecutionContext case class EmailMetadata(subject: Option[String], fromAddress: Option[String], fromName: Option[String], sentAt: Option[ExtractedDateTime]) object EmailMetadata { implicit val writes = Json.writes[EmailMetadata] } case class Email(uri: String, haveSource: Boolean, display: Option[String], metadata: Option[EmailMetadata] = None) object Email { def fromValue(v: Value)(implicit ec: ExecutionContext): Attempt[Email] = { for { uri <- v.get("uri").attempt(_.asString) maybeHaveSource <- v.get("haveSource").attemptOpt(_.asBoolean) display <- v.get("display").attemptOpt(_.asString) } yield Email(uri, maybeHaveSource.getOrElse(false), display) } implicit val writes = Json.writes[Email] } case class Neighbour(relation: String, uri: String) object Neighbour { def fromValue(v: Value)(implicit ec: ExecutionContext): Attempt[Neighbour] = { for { uri <- v.get("uri").attempt(_.asString) relation <- v.get("relation").attempt(_.asString) } yield Neighbour(relation, uri) } implicit val writes = Json.writes[Neighbour] } case class EmailNeighbours(email: Email, neighbours: Set[Neighbour]) { lazy val uris = (email.uri :: neighbours.map(_.uri).toList).distinct } object EmailNeighbours { def fromValues(email: Value, neighbours: Value)(implicit ec: ExecutionContext): Attempt[EmailNeighbours] = { for { email <- Email.fromValue(email) neighbours <- Attempt.traverse(neighbours.asList(v => v).asScala.toList)(Neighbour.fromValue) } yield EmailNeighbours(email, neighbours.toSet) } implicit val writes = Json.writes[EmailNeighbours] }