You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2020/10/28 04:53:31 UTC
[james-project] 06/10: JAMES-3436 Email/set create: Support
convenience messageId headers
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 08c28e928f34a2043d3bdb25b0bfe44ddd229628
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Oct 27 11:16:53 2020 +0700
JAMES-3436 Email/set create: Support convenience messageId headers
---
.../rfc8621/contract/EmailSetMethodContract.scala | 58 ++++++++++++++++++++++
.../james/jmap/json/EmailSetSerializer.scala | 13 ++++-
.../scala/org/apache/james/jmap/mail/Email.scala | 8 +--
.../org/apache/james/jmap/mail/EmailHeader.scala | 7 ++-
.../org/apache/james/jmap/mail/EmailSet.scala | 7 +++
5 files changed, 86 insertions(+), 7 deletions(-)
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
index c5ed96d..0e2f4bd 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
@@ -530,6 +530,64 @@ trait EmailSetMethodContract {
}
@Test
+ def createShouldSupportMessageIdHeaders(server: GuiceJamesServer): Unit = {
+ val bobPath = MailboxPath.inbox(BOB)
+ val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath)
+
+ val request = s"""{
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [
+ | ["Email/set", {
+ | "accountId": "$ACCOUNT_ID",
+ | "create": {
+ | "aaaaaa":{
+ | "mailboxIds": {
+ | "${mailboxId.serialize}": true
+ | },
+ | "references": ["aa@bb", "cc@dd"],
+ | "inReplyTo": ["ee@ff", "gg@hh"],
+ | "messageId": ["ii@jj", "kk@ll"]
+ | }
+ | }
+ | }, "c1"],
+ | ["Email/get",
+ | {
+ | "accountId": "$ACCOUNT_ID",
+ | "ids": ["#aaaaaa"],
+ | "properties": ["references", "inReplyTo", "messageId"]
+ | },
+ | "c2"]]
+ |}""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response)
+ .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
+ .inPath("methodResponses[0][1].created.aaaaaa")
+ .isEqualTo("{}".stripMargin)
+
+ assertThatJson(response)
+ .whenIgnoringPaths("methodResponses[1][1].list[0].id")
+ .inPath(s"methodResponses[1][1].list")
+ .isEqualTo(
+ s"""[{
+ | "references": ["aa@bb", "cc@dd"],
+ | "inReplyTo": ["ee@ff", "gg@hh"],
+ | "messageId": ["ii@jj", "kk@ll"]
+ |}]""".stripMargin)
+ }
+
+ @Test
def createShouldFailIfForbidden(server: GuiceJamesServer): Unit = {
val andrePath = MailboxPath.inbox(ANDRE)
val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(andrePath)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
index a5f0cd2..caacce8 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
@@ -23,12 +23,12 @@ import cats.implicits._
import eu.timepit.refined.refineV
import javax.inject.Inject
import org.apache.james.jmap.mail.EmailSet.{EmailCreationId, UnparsedMessageId, UnparsedMessageIdConstraint}
-import org.apache.james.jmap.mail.{AddressesHeaderValue, DestroyIds, EmailAddress, EmailCreationRequest, EmailCreationResponse, EmailSetRequest, EmailSetResponse, EmailSetUpdate, EmailerName, MailboxIds, Subject}
+import org.apache.james.jmap.mail.{AddressesHeaderValue, DestroyIds, EmailAddress, EmailCreationRequest, EmailCreationResponse, EmailSetRequest, EmailSetResponse, EmailSetUpdate, EmailerName, HeaderMessageId, MailboxIds, MessageIdsHeaderValue, Subject}
import org.apache.james.jmap.model.Id.IdConstraint
import org.apache.james.jmap.model.KeywordsFactory.STRICT_KEYWORDS_FACTORY
import org.apache.james.jmap.model.{Keyword, Keywords, SetError}
import org.apache.james.mailbox.model.{MailboxId, MessageId}
-import play.api.libs.json.{JsBoolean, JsError, JsNull, JsObject, JsResult, JsString, JsSuccess, JsValue, Json, OWrites, Reads, Writes}
+import play.api.libs.json.{JsArray, JsBoolean, JsError, JsNull, JsObject, JsResult, JsString, JsSuccess, JsValue, Json, OWrites, Reads, Writes}
import scala.util.Try
@@ -231,8 +231,17 @@ class EmailSetSerializer @Inject()(messageIdFactory: MessageId.Factory, mailboxI
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))))
+ }
private implicit val emailCreationRequestReads: Reads[EmailCreationRequest] = Json.reads[EmailCreationRequest]
def deserialize(input: JsValue): JsResult[EmailSetRequest] = Json.fromJson[EmailSetRequest](input)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Email.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Email.scala
index 42c2358..fb93168 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Email.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Email.scala
@@ -276,10 +276,10 @@ object EmailHeaders {
private def extractMessageId(mime4JMessage: Message, fieldName: String): MessageIdsHeaderValue =
MessageIdsHeaderValue(
Option(mime4JMessage.getHeader.getFields(fieldName))
- .map(_.asScala
- .map(_.getBody)
- .map(HeaderMessageId.from)
- .toList)
+ .map(_.asScala.toList)
+ .flatMap(fields => fields.map(field => MessageIdsHeaderValue.from(field).value)
+ .sequence
+ .map(_.flatten))
.filter(_.nonEmpty))
private def extractAddresses(mime4JMessage: Message, fieldName: String): Option[AddressesHeaderValue] =
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailHeader.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailHeader.scala
index 02f6645..9b877fb 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailHeader.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailHeader.scala
@@ -128,7 +128,12 @@ case class AddressesHeaderValue(value: List[EmailAddress]) extends EmailHeaderVa
def asMime4JMailboxList: Option[List[Mime4jMailbox]] = Some(value.map(_.asMime4JMailbox)).filter(_.nonEmpty)
}
case class GroupedAddressesHeaderValue(value: List[EmailAddressGroup]) extends EmailHeaderValue
-case class MessageIdsHeaderValue(value: Option[List[HeaderMessageId]]) extends EmailHeaderValue
+case class MessageIdsHeaderValue(value: Option[List[HeaderMessageId]]) extends EmailHeaderValue {
+ def asString: Option[String] = value.map(messageIds => messageIds
+ .map(_.value)
+ .map(messageId => s"<${messageId}>")
+ .mkString(" "))
+}
case class DateHeaderValue(value: Option[UTCDate]) extends EmailHeaderValue
case class URLsHeaderValue(value: Option[List[HeaderURL]]) extends EmailHeaderValue
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
index 42d68fc..767f021 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
@@ -33,6 +33,7 @@ import org.apache.james.mailbox.model.MessageId
import org.apache.james.mime4j.dom.Message
import org.apache.james.mime4j.dom.field.FieldName
import org.apache.james.mime4j.field.Fields
+import org.apache.james.mime4j.stream.RawField
import play.api.libs.json.JsObject
import scala.jdk.CollectionConverters._
@@ -53,6 +54,9 @@ object EmailSet {
}
case class EmailCreationRequest(mailboxIds: MailboxIds,
+ messageId: Option[MessageIdsHeaderValue],
+ references: Option[MessageIdsHeaderValue],
+ inReplyTo: Option[MessageIdsHeaderValue],
from: Option[AddressesHeaderValue],
to: Option[AddressesHeaderValue],
cc: Option[AddressesHeaderValue],
@@ -65,6 +69,9 @@ case class EmailCreationRequest(mailboxIds: MailboxIds,
receivedAt: Option[UTCDate]) {
def toMime4JMessage: Message = {
val builder = Message.Builder.of
+ references.flatMap(_.asString).map(new RawField("References", _)).foreach(builder.setField)
+ inReplyTo.flatMap(_.asString).map(new RawField("In-Reply-To", _)).foreach(builder.setField)
+ messageId.flatMap(_.asString).map(new RawField(FieldName.MESSAGE_ID, _)).foreach(builder.setField)
subject.foreach(value => builder.setSubject(value.value))
from.flatMap(_.asMime4JMailboxList).map(_.asJava).foreach(builder.setFrom)
to.flatMap(_.asMime4JMailboxList).map(_.asJava).foreach(builder.setTo)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org