in server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala [152:351]
override def asJsError: Option[JsError] = Some(JsError(s"Value associated with $property is invalid: $cause"))
}
private case class MailboxAddition(id: MailboxId) extends EntryValidation
private case class MailboxRemoval(id: MailboxId) extends EntryValidation
private case class MailboxReset(ids: MailboxIds) extends EntryValidation
private case class KeywordsReset(keywords: Keywords) extends EntryValidation
private case class KeywordAddition(keyword: Keyword) extends EntryValidation
private case class KeywordRemoval(keyword: Keyword) extends EntryValidation
}
private implicit val messageIdWrites: Writes[MessageId] = messageId => JsString(messageId.serialize)
private implicit val messageIdReads: Reads[MessageId] = {
case JsString(serializedMessageId) => Try(JsSuccess(messageIdFactory.fromString(serializedMessageId)))
.fold(_ => JsError("Invalid messageId"), messageId => messageId)
case _ => JsError("Expecting messageId to be represented by a JsString")
}
private implicit val mailboxIdsMapReads: Reads[Map[MailboxId, Boolean]] =
Reads.mapReads[MailboxId, Boolean] {s => Try(mailboxIdFactory.fromString(s)).fold(e => JsError(e.getMessage), JsSuccess(_)) } (mapMarkerReads)
private implicit val mailboxIdsReads: Reads[MailboxIds] = jsValue => mailboxIdsMapReads.reads(jsValue).map(
mailboxIdsMap => MailboxIds(mailboxIdsMap.keys.toList))
private implicit val emailSetUpdateReads: Reads[EmailSetUpdate] = {
case o: JsObject => EmailSetUpdateReads.reads(o)
case _ => JsError("Expecting a JsObject to represent an EmailSetUpdate")
}
private implicit val updatesMapReads: Reads[Map[UnparsedMessageId, JsObject]] =
Reads.mapReads[UnparsedMessageId, JsObject] {string => refineV[IdConstraint](string)
.fold(e => JsError(s"messageId needs to match id constraints: $e"),
id => JsSuccess(UnparsedMessageId(id))) }
private implicit val createsMapReads: Reads[Map[EmailCreationId, JsObject]] =
Reads.mapReads[EmailCreationId, JsObject] {s => refineV[IdConstraint](s)
.fold(e => JsError(s"email creationId needs to match id constraints: $e"),
id => JsSuccess(EmailCreationId(id))) }
private implicit val keywordReads: Reads[Keyword] = {
case jsString: JsString => Keyword.parse(jsString.value)
.fold(JsError(_),
JsSuccess(_))
case _ => JsError("Expecting a string as a keyword")
}
private implicit val keywordsMapReads: Reads[Map[Keyword, Boolean]] =
Reads.mapReads[Keyword, Boolean] {string => Keyword.parse(string).fold(JsError(_), JsSuccess(_)) } (mapMarkerReads)
private implicit val keywordsReads: Reads[Keywords] = jsValue => keywordsMapReads.reads(jsValue).flatMap(
keywordsMap => STRICT_KEYWORDS_FACTORY.fromSet(keywordsMap.keys.toSet)
.fold(e => JsError(e.getMessage), keywords => JsSuccess(keywords)))
private implicit val blobIdWrites: Writes[BlobId] = Json.valueWrites[BlobId]
private implicit val blobIdReads: Reads[BlobId] = {
case JsString(string) => BlobId.of(string)
.toEither.fold(
e => JsError(s"blobId does not match Id constraints: $e"),
blobId => JsSuccess(blobId))
case _ => JsError("blobId needs to be represented by a JsString")
}
private implicit val unparsedMessageIdWrites: Writes[UnparsedMessageId] = Json.valueWrites[UnparsedMessageId]
private implicit val unparsedMessageIdReads: Reads[UnparsedMessageId] = {
case JsString(string) => refined.refineV[IdConstraint](string)
.fold(
e => JsError(s"messageId does not match Id constraints: $e"),
id => JsSuccess(UnparsedMessageId(id)))
case _ => JsError("messageId needs to be represented by a JsString")
}
private implicit val unitWrites: Writes[Unit] = _ => JsNull
private implicit val updatedWrites: Writes[Map[MessageId, Unit]] = mapWrites[MessageId, Unit](_.serialize, unitWrites)
private implicit val notDestroyedWrites: Writes[Map[UnparsedMessageId, SetError]] = mapWrites[UnparsedMessageId, SetError](_.id.value, setErrorWrites)
private implicit val destroyIdsReads: Reads[DestroyIds] = Json.valueFormat[DestroyIds]
private implicit val destroyIdsWrites: Writes[DestroyIds] = Json.valueWrites[DestroyIds]
private implicit val emailRequestSetReads: Reads[EmailSetRequest] = Json.reads[EmailSetRequest]
private implicit val threadIdWrites: Writes[ThreadId] = Json.valueWrites[ThreadId]
private implicit val emailCreationResponseWrites: Writes[EmailCreationResponse] = Json.writes[EmailCreationResponse]
private implicit val createsMapWrites: Writes[Map[EmailCreationId, EmailCreationResponse]] =
mapWrites[EmailCreationId, EmailCreationResponse](_.id.value, emailCreationResponseWrites)
private implicit val notCreatedMapWrites: Writes[Map[EmailCreationId, SetError]] =
mapWrites[EmailCreationId, SetError](_.id.value, setErrorWrites)
private implicit val stateWrites: Writes[UuidState] = Json.valueWrites[UuidState]
private implicit val emailResponseSetWrites: OWrites[EmailSetResponse] = Json.writes[EmailSetResponse]
private implicit val subjectReads: Reads[Subject] = Json.valueReads[Subject]
private implicit val emailerNameReads: Reads[EmailerName] = Json.valueReads[EmailerName]
private implicit val headerMessageIdReads: Reads[HeaderMessageId] = Json.valueReads[HeaderMessageId]
private implicit val emailAddressReads: Reads[EmailAddress] = Json.reads[EmailAddress]
private implicit val addressesHeaderValueReads: Reads[AddressesHeaderValue] = Json.valueReads[AddressesHeaderValue]
private implicit val messageIdsHeaderValueReads: Reads[MessageIdsHeaderValue] = {
case JsArray(value) => value.map(headerMessageIdReads.reads)
.map(_.asEither)
.toList
.sequence
.fold(e => JsError(e),
ids => JsSuccess(MessageIdsHeaderValue(Some(ids).filter(_.nonEmpty))))
case jsValue => JsError(s"expected JsArray, got $jsValue")
}
private implicit val isTruncatedReads: Reads[IsTruncated] = Json.valueReads[IsTruncated]
private implicit val isEncodingProblemReads: Reads[IsEncodingProblem] = Json.valueReads[IsEncodingProblem]
private implicit val clientEmailBodyValueReads: Reads[ClientEmailBodyValue] = Json.reads[ClientEmailBodyValue]
private implicit val typeReads: Reads[Type] = Json.valueReads[Type]
private implicit val clientPartIdReads: Reads[ClientPartId] = Json.valueReads[ClientPartId]
private val rawClientBodyReads: Reads[ClientBody] = Json.reads[ClientBody]
private implicit val clientBodyReads: Reads[ClientBody] = {
case JsObject(underlying) if underlying.contains("charset") => JsError("charset must not be specified in htmlBody")
case JsObject(underlying) if underlying.contains("size") => JsError("size must not be specified in htmlBody")
case JsObject(underlying) if underlying.contains("header:Content-Transfer-Encoding") => JsError("Content-Transfer-Encoding must not be specified in htmlBody or textBody")
case JsObject(underlying) if underlying.keySet.exists(s => s.startsWith("header:Content-Transfer-Encoding:asText")) => JsError("Content-Transfer-Encoding must not be specified in htmlBody or textBody")
case o: JsObject => rawClientBodyReads.reads(o)
case _ => JsError("Expecting a JsObject to represent an ClientHtmlBody")
}
private implicit val bodyValuesReads: Reads[Map[ClientPartId, ClientEmailBodyValue]] =
Reads.mapReads[ClientPartId, ClientEmailBodyValue] {
s => Id.validate(s).fold(
e => JsError(e.getMessage),
partId => JsSuccess(ClientPartId(partId)))
}
case class EmailCreationRequestWithoutHeaders(mailboxIds: MailboxIds,
messageId: Option[MessageIdsHeaderValue],
references: Option[MessageIdsHeaderValue],
inReplyTo: Option[MessageIdsHeaderValue],
from: Option[AddressesHeaderValue],
to: Option[AddressesHeaderValue],
cc: Option[AddressesHeaderValue],
bcc: Option[AddressesHeaderValue],
sender: Option[AddressesHeaderValue],
replyTo: Option[AddressesHeaderValue],
subject: Option[Subject],
sentAt: Option[UTCDate],
keywords: Option[Keywords],
receivedAt: Option[UTCDate],
htmlBody: Option[List[ClientBody]],
textBody: Option[List[ClientBody]],
bodyValues: Option[Map[ClientPartId, ClientEmailBodyValue]],
attachments: Option[List[Attachment]]) {
def toCreationRequest(specificHeaders: List[EmailHeader]): EmailCreationRequest = EmailCreationRequest(
mailboxIds = mailboxIds,
messageId = messageId,
references = references,
inReplyTo = inReplyTo,
from = from,
to = to,
cc = cc,
bcc = bcc,
sender = sender,
replyTo = replyTo,
subject = subject,
sentAt = sentAt,
keywords = keywords,
receivedAt = receivedAt,
specificHeaders = specificHeaders,
bodyValues = bodyValues,
htmlBody = htmlBody,
textBody = textBody,
attachments = attachments)
}
private implicit val headerUrlReads: Reads[HeaderURL] = Json.valueReads[HeaderURL]
private implicit val groupNameReads: Reads[GroupName] = Json.valueReads[GroupName]
private implicit val groupReads: Reads[EmailAddressGroup] = Json.reads[EmailAddressGroup]
private implicit val dateReads: Reads[DateHeaderValue] = {
case JsNull => JsSuccess(DateHeaderValue(None))
case json: JsValue => UTCDateReads.reads(json).map(date => DateHeaderValue(Some(date)))
}
sealed trait HeaderValueReads extends Reads[EmailHeaderValue]
case object RawReads extends HeaderValueReads {
val rawReads: Reads[RawHeaderValue] = Json.valueReads[RawHeaderValue]
override def reads(json: JsValue): JsResult[EmailHeaderValue] = rawReads.reads(json)
}
case object AllReads extends HeaderValueReads {
val rawReads: Reads[RawHeaderValue] = Json.valueReads[RawHeaderValue]
override def reads(json: JsValue): JsResult[EmailHeaderValue] = rawReads.reads(json)
}
case object TextReads extends HeaderValueReads {
val textReads: Reads[TextHeaderValue] = Json.valueReads[TextHeaderValue]
override def reads(json: JsValue): JsResult[TextHeaderValue] = textReads.reads(json)
}
case object AddressesReads extends HeaderValueReads {
override def reads(json: JsValue): JsResult[AddressesHeaderValue] = addressesHeaderValueReads.reads(json)
}
case object DateReads extends HeaderValueReads {
override def reads(json: JsValue): JsResult[DateHeaderValue] = dateReads.reads(json)
}
case object MessageIdReads extends HeaderValueReads {
override def reads(json: JsValue): JsResult[MessageIdsHeaderValue] = messageIdsHeaderValueReads.reads(json)
}
case object URLReads extends HeaderValueReads {
val urlsReads: Reads[URLsHeaderValue] = {