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:25 UTC
[james-project] branch master updated (513d2cb -> 85a9af8)
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.
from 513d2cb JAMES-3436 Email/set create - syntax error validation
new 17d98a0 JAMES-3436 Email/set create: Support keywords
new 8e83fe5 JAMES-3436 Email/set create: Support receivedAt
new 26784d5 JAMES-3436 Email/set create: Support convenience address headers
new 370abe3 JAMES-3436 Email/set create: Multiple Sender addresses should be supported
new f781ad0 JAMES-3436 Email/set create: Support sentAt
new 08c28e9 JAMES-3436 Email/set create: Support convenience messageId headers
new 432f2d6 JAMES-3408 Limit concurrency when retrieving mailbox counters
new 4f6529b JAMES-3437 MemoryMailQueueFactory should be a singleton
new 05a38ba MAILBOX-401 Demonstrate '-' causes address matching to fail
new 85a9af8 Update RabbitMQConnectionFactory.java
The 10 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../rabbitmq/RabbitMQConnectionFactory.java | 4 +
.../ElasticSearchIntegrationTest.java | 97 ++++++
.../james/mailbox/store/StoreMailboxManager.java | 4 +-
.../modules/server/MemoryMailQueueModule.java | 3 +-
.../rfc8621/contract/EmailGetMethodContract.scala | 6 +-
.../rfc8621/contract/EmailSetMethodContract.scala | 357 ++++++++++++++++++++-
.../james/jmap/json/EmailGetSerializer.scala | 3 +-
.../james/jmap/json/EmailSetSerializer.scala | 16 +-
.../scala/org/apache/james/jmap/json/package.scala | 8 +
.../scala/org/apache/james/jmap/mail/Email.scala | 15 +-
.../org/apache/james/jmap/mail/EmailAddress.scala | 23 +-
.../org/apache/james/jmap/mail/EmailHeader.scala | 13 +-
.../org/apache/james/jmap/mail/EmailSet.scala | 31 +-
.../apache/james/jmap/method/EmailSetMethod.scala | 12 +-
.../integration/WebAdminServerIntegrationTest.java | 3 +-
15 files changed, 560 insertions(+), 35 deletions(-)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 07/10: JAMES-3408 Limit concurrency when retrieving
mailbox counters
Posted by bt...@apache.org.
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 432f2d686d693b6bedb5d891fd0f15cfdcaa020b
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Oct 27 12:52:25 2020 +0700
JAMES-3408 Limit concurrency when retrieving mailbox counters
4 in parrallel instead of 128 should limit pressure on the DB
---
.../main/java/org/apache/james/mailbox/store/StoreMailboxManager.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index 97c1972..6e075c0 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -650,11 +650,13 @@ public class StoreMailboxManager implements MailboxManager {
private Function<Flux<Mailbox>, Flux<MailboxMetaData>> withCounters(MailboxSession session, List<Mailbox> mailboxes) {
MessageMapper messageMapper = mailboxSessionMapperFactory.getMessageMapper(session);
+ int concurrency = 4;
return mailboxFlux -> mailboxFlux
.flatMap(mailbox -> retrieveCounters(messageMapper, mailbox, session)
.map(Throwing.<MailboxCounters, MailboxMetaData>function(
counters -> toMailboxMetadata(session, mailboxes, mailbox, counters))
- .sneakyThrow()));
+ .sneakyThrow()),
+ concurrency);
}
private Function<Flux<Mailbox>, Flux<MailboxMetaData>> withoutCounters(MailboxSession session, List<Mailbox> mailboxes) {
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 05/10: JAMES-3436 Email/set create: Support sentAt
Posted by bt...@apache.org.
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 f781ad0c310f5941f6df56de3bccb007a0706706
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Oct 27 09:32:12 2020 +0700
JAMES-3436 Email/set create: Support sentAt
---
.../rfc8621/contract/EmailSetMethodContract.scala | 58 ++++++++++++++++++++++
.../org/apache/james/jmap/mail/EmailSet.scala | 3 ++
2 files changed, 61 insertions(+)
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 9cfbeec..c5ed96d 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
@@ -472,6 +472,64 @@ trait EmailSetMethodContract {
}
@Test
+ def createShouldSupportSentAt(server: GuiceJamesServer): Unit = {
+ val bobPath = MailboxPath.inbox(BOB)
+ val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath)
+ val sentAt = ZonedDateTime.now().minusDays(1)
+
+ 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
+ | },
+ | "sentAt": "${UTCDate(sentAt).asUTC.format(UTC_DATE_FORMAT)}"
+ | }
+ | }
+ | }, "c1"],
+ | ["Email/get",
+ | {
+ | "accountId": "$ACCOUNT_ID",
+ | "ids": ["#aaaaaa"],
+ | "properties": ["mailboxIds", "sentAt"]
+ | },
+ | "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"""[{
+ | "mailboxIds": {
+ | "${mailboxId.serialize}": true
+ | },
+ | "sentAt": "${UTCDate(sentAt).asUTC.format(UTC_DATE_FORMAT)}"
+ |}]""".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/mail/EmailSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
index f64db7e..42d68fc 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
@@ -19,6 +19,7 @@
package org.apache.james.jmap.mail
import java.nio.charset.StandardCharsets
+import java.util.Date
import eu.timepit.refined
import eu.timepit.refined.api.Refined
@@ -59,6 +60,7 @@ case class EmailCreationRequest(mailboxIds: MailboxIds,
sender: Option[AddressesHeaderValue],
replyTo: Option[AddressesHeaderValue],
subject: Option[Subject],
+ sentAt: Option[UTCDate],
keywords: Option[Keywords],
receivedAt: Option[UTCDate]) {
def toMime4JMessage: Message = {
@@ -70,6 +72,7 @@ case class EmailCreationRequest(mailboxIds: MailboxIds,
bcc.flatMap(_.asMime4JMailboxList).map(_.asJava).foreach(builder.setBcc)
sender.flatMap(_.asMime4JMailboxList).map(_.asJava).map(Fields.addressList(FieldName.SENDER, _)).foreach(builder.setField)
replyTo.flatMap(_.asMime4JMailboxList).map(_.asJava).foreach(builder.setReplyTo)
+ sentAt.map(_.asUTC).map(_.toInstant).map(Date.from).foreach(builder.setDate)
builder.setBody("", StandardCharsets.UTF_8)
builder.build()
}
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 03/10: JAMES-3436 Email/set create: Support
convenience address headers
Posted by bt...@apache.org.
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 26784d5868513db3dd13fae221c369896e141932
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Oct 26 12:44:38 2020 +0100
JAMES-3436 Email/set create: Support convenience address headers
---
.../rfc8621/contract/EmailGetMethodContract.scala | 2 +-
.../rfc8621/contract/EmailSetMethodContract.scala | 62 ++++++++++++++++++++++
.../james/jmap/json/EmailGetSerializer.scala | 3 +-
.../james/jmap/json/EmailSetSerializer.scala | 5 +-
.../scala/org/apache/james/jmap/json/package.scala | 8 +++
.../scala/org/apache/james/jmap/mail/Email.scala | 2 +-
.../org/apache/james/jmap/mail/EmailAddress.scala | 23 ++++----
.../org/apache/james/jmap/mail/EmailHeader.scala | 6 ++-
.../org/apache/james/jmap/mail/EmailSet.scala | 15 ++++++
9 files changed, 110 insertions(+), 16 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/EmailGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
index a6ca953..47a5c3e 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
@@ -6223,7 +6223,7 @@ trait EmailGetMethodContract {
| "c1"]]
|}""".stripMargin)
.when
- .post
+ .post.prettyPeek
.`then`
.statusCode(SC_OK)
.contentType(JSON)
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 64bbdf6..b04ca96 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
@@ -237,6 +237,68 @@ trait EmailSetMethodContract {
}
@Test
+ def createShouldHandleAddressHeaders(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},
+ | "cc": [{"name": "MODALİF", "email": "modalif@domain.tld"}],
+ | "bcc": [{"email": "benwa@apache.org"}],
+ | "to": [{"email": "rcpt1@apache.org"}, {"email": "rcpt2@apache.org"}],
+ | "from": [{"email": "rcpt2@apache.org"}, {"email": "rcpt3@apache.org"}],
+ | "sender": [{"email": "rcpt4@apache.org"}],
+ | "replyTo": [{"email": "rcpt6@apache.org"}, {"email": "rcpt7@apache.org"}]
+ | }
+ | }
+ | }, "c1"],
+ | ["Email/get",
+ | {
+ | "accountId": "$ACCOUNT_ID",
+ | "ids": ["#aaaaaa"],
+ | "properties": ["cc", "bcc", "sender", "from", "to", "replyTo"]
+ | },
+ | "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"""[{
+ | "cc": [{"name": "MODALİF", "email": "modalif@domain.tld"}],
+ | "bcc": [{"email": "benwa@apache.org"}],
+ | "to": [{"email": "rcpt1@apache.org"}, {"email": "rcpt2@apache.org"}],
+ | "from": [{"email": "rcpt2@apache.org"}, {"email": "rcpt3@apache.org"}],
+ | "sender": [{"email": "rcpt4@apache.org"}],
+ | "replyTo": [{"email": "rcpt6@apache.org"}, {"email": "rcpt7@apache.org"}]
+ |}]""".stripMargin)
+ }
+
+ @Test
def createShouldSupportKeywords(server: GuiceJamesServer): Unit = {
val bobPath = MailboxPath.inbox(BOB)
val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
index 9ec87f6..e8f3c54 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
@@ -20,7 +20,7 @@
package org.apache.james.jmap.json
import org.apache.james.jmap.api.model.Preview
-import org.apache.james.jmap.mail.{Address, AddressesHeaderValue, BlobId, Charset, DateHeaderValue, Disposition, EmailAddress, EmailAddressGroup, EmailBody, EmailBodyMetadata, EmailBodyPart, EmailBodyValue, EmailFastView, EmailFullView, EmailGetRequest, EmailGetResponse, EmailHeader, EmailHeaderName, EmailHeaderValue, EmailHeaderView, EmailHeaders, EmailIds, EmailMetadata, EmailMetadataView, EmailNotFound, EmailView, EmailerName, FetchAllBodyValues, FetchHTMLBodyValues, FetchTextBodyValu [...]
+import org.apache.james.jmap.mail.{AddressesHeaderValue, BlobId, Charset, DateHeaderValue, Disposition, EmailAddress, EmailAddressGroup, EmailBody, EmailBodyMetadata, EmailBodyPart, EmailBodyValue, EmailFastView, EmailFullView, EmailGetRequest, EmailGetResponse, EmailHeader, EmailHeaderName, EmailHeaderValue, EmailHeaderView, EmailHeaders, EmailIds, EmailMetadata, EmailMetadataView, EmailNotFound, EmailView, EmailerName, FetchAllBodyValues, FetchHTMLBodyValues, FetchTextBodyValues, Group [...]
import org.apache.james.jmap.model._
import org.apache.james.mailbox.model.{Cid, MailboxId, MessageId}
import play.api.libs.functional.syntax._
@@ -45,7 +45,6 @@ object EmailGetSerializer {
private implicit val languageWrites: Writes[Language] = Json.valueWrites[Language]
private implicit val locationWrites: Writes[Location] = Json.valueWrites[Location]
private implicit val emailerNameWrites: Writes[EmailerName] = Json.valueWrites[EmailerName]
- private implicit val addressWrites: Writes[Address] = Json.valueWrites[Address]
private implicit val emailAddressWrites: Writes[EmailAddress] = Json.writes[EmailAddress]
private implicit val headerMessageIdWrites: Writes[HeaderMessageId] = Json.valueWrites[HeaderMessageId]
private implicit val isEncodingProblemWrites: Writes[IsEncodingProblem] = Json.valueWrites[IsEncodingProblem]
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 e36e3ca..a5f0cd2 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,7 +23,7 @@ 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.{DestroyIds, EmailCreationRequest, EmailCreationResponse, EmailSetRequest, EmailSetResponse, EmailSetUpdate, MailboxIds, Subject}
+import org.apache.james.jmap.mail.{AddressesHeaderValue, DestroyIds, EmailAddress, EmailCreationRequest, EmailCreationResponse, EmailSetRequest, EmailSetResponse, EmailSetUpdate, EmailerName, MailboxIds, 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}
@@ -230,6 +230,9 @@ class EmailSetSerializer @Inject()(messageIdFactory: MessageId.Factory, mailboxI
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 emailAddressReads: Reads[EmailAddress] = Json.reads[EmailAddress]
+ private implicit val addressesHeaderValueReads: Reads[AddressesHeaderValue] = Json.valueReads[AddressesHeaderValue]
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/json/package.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/package.scala
index 05eaeab..2c4e5c2 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/package.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/package.scala
@@ -23,6 +23,7 @@ import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import eu.timepit.refined.api.{RefType, Validate}
+import org.apache.james.core.MailAddress
import org.apache.james.jmap.model.Id.Id
import org.apache.james.jmap.model.SetError.SetErrorDescription
import org.apache.james.jmap.model.{AccountId, Properties, SetError, UTCDate}
@@ -101,6 +102,13 @@ package object json {
private[json] implicit val propertiesFormat: Format[Properties] = Json.valueFormat[Properties]
private[json] implicit val setErrorDescriptionWrites: Writes[SetErrorDescription] = Json.valueWrites[SetErrorDescription]
private[json] implicit val setErrorWrites: Writes[SetError] = Json.writes[SetError]
+ private[json] implicit val mailAddressWrites: Writes[MailAddress] = mailAddress => JsString(mailAddress.asString)
+ private[json] implicit val mailAddressReads: Reads[MailAddress] = {
+ case JsString(value) => Try(new MailAddress(value))
+ .fold(e => JsError(e.getMessage),
+ mailAddress => JsSuccess(mailAddress))
+ case _ => JsError("mail address needs to be represented with a JsString")
+ }
private[json] implicit val utcDateWrites: Writes[UTCDate] =
utcDate => JsString(utcDate.asUTC.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssX")))
}
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 9174ef9..0804583 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
@@ -286,7 +286,7 @@ object EmailHeaders {
.flatMap {
case f: AddressListField => Some(AddressesHeaderValue(EmailAddress.from(f.getAddressList)))
case f: MailboxListField => Some(AddressesHeaderValue(EmailAddress.from(f.getMailboxList)))
- case f: MailboxField => Some(AddressesHeaderValue(List(EmailAddress.from(f.getMailbox))))
+ case f: MailboxField => Some(AddressesHeaderValue(List(EmailAddress.from(f.getMailbox).toOption).flatten))
case _ => None
}
.filter(_.value.nonEmpty)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailAddress.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailAddress.scala
index 59f3a6c..80548d6 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailAddress.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailAddress.scala
@@ -19,9 +19,11 @@
package org.apache.james.jmap.mail
+import org.apache.james.core.MailAddress
import org.apache.james.mime4j.dom.address.{AddressList, MailboxList, Mailbox => Mime4jMailbox}
import scala.jdk.CollectionConverters._
+import scala.util.Try
object EmailerName {
def from(value: String): EmailerName = EmailerName(value.strip())
@@ -29,8 +31,6 @@ object EmailerName {
case class EmailerName(value: String) extends AnyVal
-case class Address(value: String) extends AnyVal
-
object EmailAddress {
def from(addressList: AddressList): List[EmailAddress] = Option(addressList)
.map(addressList => from(addressList.flatten()))
@@ -39,13 +39,18 @@ object EmailAddress {
def from(addressList: MailboxList): List[EmailAddress] =
addressList.asScala
.toList
- .map(from)
+ .flatMap(mailbox => from(mailbox).toOption)
- def from(mailbox: Mime4jMailbox): EmailAddress = {
- EmailAddress(
- name = Option(mailbox.getName).map(EmailerName.from),
- email = Address(mailbox.getAddress))
- }
+ def from(mailbox: Mime4jMailbox): Try[EmailAddress] =
+ Try(new MailAddress(mailbox.getAddress))
+ .map(email => EmailAddress(
+ name = Option(mailbox.getName).map(EmailerName.from),
+ email = email))
}
-case class EmailAddress(name: Option[EmailerName], email: Address)
+case class EmailAddress(name: Option[EmailerName], email: MailAddress) {
+ val asMime4JMailbox: Mime4jMailbox = new Mime4jMailbox(
+ name.map(_.value).orNull,
+ email.getLocalPart,
+ email.getDomain.asString)
+}
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 8c8247c..02f6645 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
@@ -71,7 +71,7 @@ object GroupedAddressesHeaderValue extends EmailHeaderValue {
case mailbox: Mime4jMailbox => Some(mailbox)
case _ => None
})
- .map(EmailAddress.from(_))
+ .flatMap(EmailAddress.from(_).toOption)
GroupedAddressesHeaderValue(List(EmailAddressGroup(None, addressesWithoutGroup)) ++ groups)
}
@@ -124,7 +124,9 @@ case class EmailHeaderName(value: String) extends AnyVal
sealed trait EmailHeaderValue
case class RawHeaderValue(value: String) extends EmailHeaderValue
case class TextHeaderValue(value: String) extends EmailHeaderValue
-case class AddressesHeaderValue(value: List[EmailAddress]) extends EmailHeaderValue
+case class AddressesHeaderValue(value: List[EmailAddress]) extends EmailHeaderValue {
+ 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 DateHeaderValue(value: Option[UTCDate]) 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 90c9c41..f64db7e 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
@@ -30,8 +30,11 @@ import org.apache.james.jmap.model.State.State
import org.apache.james.jmap.model.{AccountId, Keywords, SetError, UTCDate}
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 play.api.libs.json.JsObject
+import scala.jdk.CollectionConverters._
import scala.util.{Right, Try}
object EmailSet {
@@ -49,12 +52,24 @@ object EmailSet {
}
case class EmailCreationRequest(mailboxIds: MailboxIds,
+ from: Option[AddressesHeaderValue],
+ to: Option[AddressesHeaderValue],
+ cc: Option[AddressesHeaderValue],
+ bcc: Option[AddressesHeaderValue],
+ sender: Option[AddressesHeaderValue],
+ replyTo: Option[AddressesHeaderValue],
subject: Option[Subject],
keywords: Option[Keywords],
receivedAt: Option[UTCDate]) {
def toMime4JMessage: Message = {
val builder = Message.Builder.of
subject.foreach(value => builder.setSubject(value.value))
+ from.flatMap(_.asMime4JMailboxList).map(_.asJava).foreach(builder.setFrom)
+ to.flatMap(_.asMime4JMailboxList).map(_.asJava).foreach(builder.setTo)
+ cc.flatMap(_.asMime4JMailboxList).map(_.asJava).foreach(builder.setCc)
+ bcc.flatMap(_.asMime4JMailboxList).map(_.asJava).foreach(builder.setBcc)
+ sender.flatMap(_.asMime4JMailboxList).map(_.asJava).map(Fields.addressList(FieldName.SENDER, _)).foreach(builder.setField)
+ replyTo.flatMap(_.asMime4JMailboxList).map(_.asJava).foreach(builder.setReplyTo)
builder.setBody("", StandardCharsets.UTF_8)
builder.build()
}
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 10/10: Update RabbitMQConnectionFactory.java
Posted by bt...@apache.org.
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 85a9af8b818afff8a4a380f6021c63ce9fdef46a
Author: wnfkwnfk <45...@users.noreply.github.com>
AuthorDate: Tue Oct 27 22:01:20 2020 +0800
Update RabbitMQConnectionFactory.java
when rabbitmq change guest's password, it cannot be connected and will throw exception:
An unexpected connection driver error occured (Exception message: Socket closed)
so we should set username and password here to make it work correctly
---
.../org/apache/james/backends/rabbitmq/RabbitMQConnectionFactory.java | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConnectionFactory.java b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConnectionFactory.java
index 36989f9..cb45fc7 100644
--- a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConnectionFactory.java
+++ b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConnectionFactory.java
@@ -50,6 +50,10 @@ public class RabbitMQConnectionFactory {
connectionFactory.setChannelRpcTimeout(rabbitMQConfiguration.getChannelRpcTimeoutInMs());
connectionFactory.setConnectionTimeout(rabbitMQConfiguration.getConnectionTimeoutInMs());
connectionFactory.setNetworkRecoveryInterval(rabbitMQConfiguration.getNetworkRecoveryIntervalInMs());
+
+ connectionFactory.setUsername(rabbitMQConfiguration.getManagementCredentials().getUser());
+ connectionFactory.setPassword(String.valueOf(rabbitMQConfiguration.getManagementCredentials().getPassword()));
+
return connectionFactory;
} catch (Exception e) {
throw new RuntimeException(e);
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 08/10: JAMES-3437 MemoryMailQueueFactory should be
a singleton
Posted by bt...@apache.org.
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 4f6529b36c411b89a2821f9e98bf2002f02d35aa
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Oct 27 13:48:37 2020 +0700
JAMES-3437 MemoryMailQueueFactory should be a singleton
---
.../java/org/apache/james/modules/server/MemoryMailQueueModule.java | 3 ++-
.../james/webadmin/integration/WebAdminServerIntegrationTest.java | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/server/MemoryMailQueueModule.java b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/server/MemoryMailQueueModule.java
index 8af5b16..8a05148 100644
--- a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/server/MemoryMailQueueModule.java
+++ b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/server/MemoryMailQueueModule.java
@@ -25,13 +25,14 @@ import org.apache.james.queue.memory.MemoryMailQueueFactory;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
+import com.google.inject.Scopes;
import com.google.inject.Singleton;
public class MemoryMailQueueModule extends AbstractModule {
@Override
protected void configure() {
-
+ bind(MemoryMailQueueFactory.class).in(Scopes.SINGLETON);
}
@Provides
diff --git a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
index 992a2e9..1730a1d 100644
--- a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
+++ b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
@@ -100,7 +100,8 @@ public abstract class WebAdminServerIntegrationTest {
when()
.get(MailQueueRoutes.BASE_URL)
.then()
- .statusCode(HttpStatus.OK_200);
+ .statusCode(HttpStatus.OK_200)
+ .body("", containsInAnyOrder("spool", "outgoing"));
}
@Test
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 09/10: MAILBOX-401 Demonstrate '-' causes address
matching to fail
Posted by bt...@apache.org.
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 05a38ba764e990683a1126f897612e8e41f0ec3a
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Oct 28 08:50:53 2020 +0700
MAILBOX-401 Demonstrate '-' causes address matching to fail
---
.../ElasticSearchIntegrationTest.java | 97 ++++++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
index 043a3dc..46eb518 100644
--- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
+++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
@@ -51,6 +51,7 @@ import org.apache.james.metrics.tests.RecordingMetricFactory;
import org.apache.james.mime4j.dom.Message;
import org.apache.james.mime4j.stream.RawField;
import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -292,4 +293,100 @@ class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest {
assertThat(messageManager.search(SearchQuery.of(SearchQuery.address(SearchQuery.AddressType.To, "bob@other.tld")), session))
.containsOnly(messageId2.getUid());
}
+
+ @Disabled("MAILBOX-401 '-' causes address matching to fail")
+ @Test
+ void localPartShouldBeMatchedWhenHyphen() throws Exception {
+ MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, INBOX);
+ MailboxSession session = MailboxSessionUtil.create(USERNAME);
+ MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+
+ Message.Builder messageBuilder = Message.Builder
+ .of()
+ .setSubject("test")
+ .setBody("testmail", StandardCharsets.UTF_8);
+
+ ComposedMessageId messageId1 = messageManager.appendMessage(
+ MessageManager.AppendCommand.builder().build(
+ messageBuilder
+ .addField(new RawField("To", "alice-test@domain.tld"))
+ .build()),
+ session).getId();
+
+ ComposedMessageId messageId2 = messageManager.appendMessage(
+ MessageManager.AppendCommand.builder().build(
+ messageBuilder
+ .addField(new RawField("To", "bob@other.tld"))
+ .build()),
+ session).getId();
+
+ elasticSearch.awaitForElasticSearch();
+
+ assertThat(messageManager.search(SearchQuery.of(SearchQuery.address(SearchQuery.AddressType.To, "alice-test")), session))
+ .containsOnly(messageId2.getUid());
+ }
+
+ @Disabled("MAILBOX-401 '-' causes address matching to fail")
+ @Test
+ void addressShouldBeMatchedWhenHyphen() throws Exception {
+ MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, INBOX);
+ MailboxSession session = MailboxSessionUtil.create(USERNAME);
+ MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+
+ Message.Builder messageBuilder = Message.Builder
+ .of()
+ .setSubject("test")
+ .setBody("testmail", StandardCharsets.UTF_8);
+
+ ComposedMessageId messageId1 = messageManager.appendMessage(
+ MessageManager.AppendCommand.builder().build(
+ messageBuilder
+ .addField(new RawField("To", "alice-test@domain.tld"))
+ .build()),
+ session).getId();
+
+ ComposedMessageId messageId2 = messageManager.appendMessage(
+ MessageManager.AppendCommand.builder().build(
+ messageBuilder
+ .addField(new RawField("To", "bob@other.tld"))
+ .build()),
+ session).getId();
+
+ elasticSearch.awaitForElasticSearch();
+
+ assertThat(messageManager.search(SearchQuery.of(SearchQuery.address(SearchQuery.AddressType.To, "alice-test@domain.tld")), session))
+ .containsOnly(messageId1.getUid());
+ }
+
+ @Disabled("MAILBOX-401 '-' causes address matching to fail")
+ @Test
+ void domainPartShouldBeMatchedWhenHyphen() throws Exception {
+ MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, INBOX);
+ MailboxSession session = MailboxSessionUtil.create(USERNAME);
+ MessageManager messageManager = storeMailboxManager.getMailbox(mailboxPath, session);
+
+ Message.Builder messageBuilder = Message.Builder
+ .of()
+ .setSubject("test")
+ .setBody("testmail", StandardCharsets.UTF_8);
+
+ ComposedMessageId messageId1 = messageManager.appendMessage(
+ MessageManager.AppendCommand.builder().build(
+ messageBuilder
+ .addField(new RawField("To", "alice@domain-test.tld"))
+ .build()),
+ session).getId();
+
+ ComposedMessageId messageId2 = messageManager.appendMessage(
+ MessageManager.AppendCommand.builder().build(
+ messageBuilder
+ .addField(new RawField("To", "bob@other.tld"))
+ .build()),
+ session).getId();
+
+ elasticSearch.awaitForElasticSearch();
+
+ assertThat(messageManager.search(SearchQuery.of(SearchQuery.address(SearchQuery.AddressType.To, "domain-test.tld")), session))
+ .containsOnly(messageId1.getUid());
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 06/10: JAMES-3436 Email/set create: Support
convenience messageId headers
Posted by bt...@apache.org.
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
[james-project] 04/10: JAMES-3436 Email/set create: Multiple Sender
addresses should be supported
Posted by bt...@apache.org.
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 370abe372817223e6513797360c01b0439733dc9
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Oct 27 09:00:37 2020 +0700
JAMES-3436 Email/set create: Multiple Sender addresses should be supported
---
.../rfc8621/contract/EmailGetMethodContract.scala | 8 +++-
.../rfc8621/contract/EmailSetMethodContract.scala | 52 ++++++++++++++++++++++
.../scala/org/apache/james/jmap/mail/Email.scala | 7 ++-
3 files changed, 63 insertions(+), 4 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/EmailGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
index 47a5c3e..01ae19e 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
@@ -2010,7 +2010,7 @@ trait EmailGetMethodContract {
}
@Test
- def senderPropertyShouldKeepFirstValue(server: GuiceJamesServer): Unit = {
+ def senderPropertyShouldDisplayBothValues(server: GuiceJamesServer): Unit = {
val message: Message = Message.Builder
.of
.addField(new RawField("Sender",
@@ -2056,7 +2056,11 @@ trait EmailGetMethodContract {
| {
| "name": "user1",
| "email": "user1@domain.tld"
+ | },
+ | {
+ | "email": "user2@domain.tld"
| }
+ |
| ]
|}""".stripMargin)
}
@@ -6223,7 +6227,7 @@ trait EmailGetMethodContract {
| "c1"]]
|}""".stripMargin)
.when
- .post.prettyPeek
+ .post
.`then`
.statusCode(SC_OK)
.contentType(JSON)
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 b04ca96..9cfbeec 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
@@ -299,6 +299,58 @@ trait EmailSetMethodContract {
}
@Test
+ def createWithMultipleSenderShouldNotCrash(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},
+ | "sender": [{"email": "rcpt4@apache.org"}, {"email": "rcpt3@apache.org"}]
+ | }
+ | }
+ | }, "c1"],
+ | ["Email/get",
+ | {
+ | "accountId": "$ACCOUNT_ID",
+ | "ids": ["#aaaaaa"],
+ | "properties": ["sender"]
+ | },
+ | "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"""[{
+ | "sender": [{"email": "rcpt4@apache.org"}, {"email": "rcpt3@apache.org"}]
+ |}]""".stripMargin)
+ }
+
+ @Test
def createShouldSupportKeywords(server: GuiceJamesServer): Unit = {
val bobPath = MailboxPath.inbox(BOB)
val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath)
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 0804583..42c2358 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
@@ -45,8 +45,9 @@ import org.apache.james.mailbox.{MailboxSession, MessageIdManager}
import org.apache.james.mime4j.codec.DecodeMonitor
import org.apache.james.mime4j.dom.field.{AddressListField, DateTimeField, MailboxField, MailboxListField}
import org.apache.james.mime4j.dom.{Header, Message}
+import org.apache.james.mime4j.field.AddressListFieldLenientImpl
import org.apache.james.mime4j.message.DefaultMessageBuilder
-import org.apache.james.mime4j.stream.{Field, MimeConfig}
+import org.apache.james.mime4j.stream.{Field, MimeConfig, RawFieldParser}
import org.apache.james.mime4j.util.MimeUtil
import org.slf4j.{Logger, LoggerFactory}
import reactor.core.scala.publisher.{SFlux, SMono}
@@ -286,7 +287,9 @@ object EmailHeaders {
.flatMap {
case f: AddressListField => Some(AddressesHeaderValue(EmailAddress.from(f.getAddressList)))
case f: MailboxListField => Some(AddressesHeaderValue(EmailAddress.from(f.getMailboxList)))
- case f: MailboxField => Some(AddressesHeaderValue(List(EmailAddress.from(f.getMailbox).toOption).flatten))
+ case f: MailboxField =>
+ val asMailboxListField = AddressListFieldLenientImpl.PARSER.parse(RawFieldParser.DEFAULT.parseField(f.getRaw), DecodeMonitor.SILENT)
+ Some(AddressesHeaderValue(EmailAddress.from(asMailboxListField.getAddressList)))
case _ => None
}
.filter(_.value.nonEmpty)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 02/10: JAMES-3436 Email/set create: Support
receivedAt
Posted by bt...@apache.org.
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 8e83fe5427419109694c5403c9fcdec507ac3244
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Oct 26 08:45:56 2020 +0100
JAMES-3436 Email/set create: Support receivedAt
---
.../rfc8621/contract/EmailSetMethodContract.scala | 63 ++++++++++++++++++++++
.../org/apache/james/jmap/mail/EmailSet.scala | 5 +-
.../apache/james/jmap/method/EmailSetMethod.scala | 11 ++--
3 files changed, 71 insertions(+), 8 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 6992bb6..64bbdf6 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
@@ -20,6 +20,8 @@ package org.apache.james.jmap.rfc8621.contract
import java.io.ByteArrayInputStream
import java.nio.charset.StandardCharsets
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
import java.util.Date
import io.netty.handler.codec.http.HttpHeaderNames.ACCEPT
@@ -31,6 +33,7 @@ import org.apache.http.HttpStatus.SC_OK
import org.apache.james.GuiceJamesServer
import org.apache.james.jmap.draft.{JmapGuiceProbe, MessageIdProbe}
import org.apache.james.jmap.http.UserCredential
+import org.apache.james.jmap.model.UTCDate
import org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, ACCOUNT_ID, ANDRE, ANDRE_PASSWORD, BOB, BOB_PASSWORD, DOMAIN, authScheme, baseRequestSpecBuilder}
import org.apache.james.mailbox.FlagsBuilder
import org.apache.james.mailbox.MessageManager.AppendCommand
@@ -48,6 +51,8 @@ import org.junit.jupiter.params.provider.ValueSource
import scala.jdk.CollectionConverters._
trait EmailSetMethodContract {
+ private lazy val UTC_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssX")
+
@BeforeEach
def setUp(server: GuiceJamesServer): Unit = {
server.getProbe(classOf[DataProbeImpl])
@@ -295,6 +300,64 @@ trait EmailSetMethodContract {
}
@Test
+ def createShouldSupportReceivedAt(server: GuiceJamesServer): Unit = {
+ val bobPath = MailboxPath.inbox(BOB)
+ val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath)
+ val receivedAt = ZonedDateTime.now().minusDays(1)
+
+ 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
+ | },
+ | "receivedAt": "${UTCDate(receivedAt).asUTC.format(UTC_DATE_FORMAT)}"
+ | }
+ | }
+ | }, "c1"],
+ | ["Email/get",
+ | {
+ | "accountId": "$ACCOUNT_ID",
+ | "ids": ["#aaaaaa"],
+ | "properties": ["mailboxIds", "receivedAt"]
+ | },
+ | "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"""[{
+ | "mailboxIds": {
+ | "${mailboxId.serialize}": true
+ | },
+ | "receivedAt": "${UTCDate(receivedAt).asUTC.format(UTC_DATE_FORMAT)}"
+ |}]""".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/mail/EmailSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
index baedcf7..90c9c41 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
@@ -27,7 +27,7 @@ import org.apache.james.jmap.mail.EmailSet.{EmailCreationId, UnparsedMessageId}
import org.apache.james.jmap.method.WithAccountId
import org.apache.james.jmap.model.Id.Id
import org.apache.james.jmap.model.State.State
-import org.apache.james.jmap.model.{AccountId, Keywords, SetError}
+import org.apache.james.jmap.model.{AccountId, Keywords, SetError, UTCDate}
import org.apache.james.mailbox.model.MessageId
import org.apache.james.mime4j.dom.Message
import play.api.libs.json.JsObject
@@ -50,7 +50,8 @@ object EmailSet {
case class EmailCreationRequest(mailboxIds: MailboxIds,
subject: Option[Subject],
- keywords: Option[Keywords]) {
+ keywords: Option[Keywords],
+ receivedAt: Option[UTCDate]) {
def toMime4JMessage: Message = {
val builder = Message.Builder.of
subject.foreach(value => builder.setSubject(value.value))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetMethod.scala
index 759cd30..5cf9af6 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetMethod.scala
@@ -18,6 +18,8 @@
****************************************************************/
package org.apache.james.jmap.method
+import java.time.ZonedDateTime
+import java.util.Date
import java.util.function.Consumer
import com.google.common.collect.ImmutableList
@@ -26,22 +28,18 @@ import javax.inject.Inject
import javax.mail.Flags
import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.{EmailSetSerializer, ResponseSerializer}
-import org.apache.james.jmap.mail.EmailSet.UnparsedMessageId
-import org.apache.james.jmap.mail.{DestroyIds, EmailSet, EmailSetRequest, EmailSetResponse, MailboxIds, ValidatedEmailSetUpdate}
import org.apache.james.jmap.mail.EmailSet.{EmailCreationId, UnparsedMessageId}
-import org.apache.james.jmap.mail.{DestroyIds, EmailCreationRequest, EmailCreationResponse, EmailSet, EmailSetRequest, EmailSetResponse, EmailSetUpdate, MailboxIds, ValidatedEmailSetUpdate}
+import org.apache.james.jmap.mail.{DestroyIds, EmailCreationRequest, EmailCreationResponse, EmailSet, EmailSetRequest, EmailSetResponse, MailboxIds, ValidatedEmailSetUpdate}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.DefaultCapabilities.{CORE_CAPABILITY, MAIL_CAPABILITY}
import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
import org.apache.james.jmap.model.KeywordsFactory.LENIENT_KEYWORDS_FACTORY
import org.apache.james.jmap.model.SetError.SetErrorDescription
-import org.apache.james.jmap.model.{Capabilities, ClientId, Id, Invocation, ServerId, SetError, State}
+import org.apache.james.jmap.model.{Capabilities, ClientId, Id, Invocation, ServerId, SetError, State, UTCDate}
import org.apache.james.mailbox.MessageManager.{AppendCommand, FlagsUpdateMode}
import org.apache.james.mailbox.exception.MailboxNotFoundException
import org.apache.james.mailbox.model.{ComposedMessageIdWithMetaData, DeleteResult, MailboxId, MessageId, MessageRange}
import org.apache.james.mailbox.{MailboxManager, MailboxSession, MessageIdManager, MessageManager}
-import org.apache.james.mailbox.model.{ComposedMessageIdWithMetaData, DeleteResult, MailboxId, MessageId}
-import org.apache.james.mailbox.{MailboxManager, MailboxSession, MessageIdManager}
import org.apache.james.metrics.api.MetricFactory
import play.api.libs.json.{JsError, JsObject, JsSuccess}
import reactor.core.scala.publisher.{SFlux, SMono}
@@ -232,6 +230,7 @@ class EmailSetMethod @Inject()(serializer: EmailSetSerializer,
.appendMessage(AppendCommand.builder()
.recent()
.withFlags(request.keywords.map(_.asFlags).getOrElse(new Flags()))
+ .withInternalDate(Date.from(request.receivedAt.getOrElse(UTCDate(ZonedDateTime.now())).asUTC.toInstant))
.build(request.toMime4JMessage),
mailboxSession)
CreationSuccess(clientId, EmailCreationResponse(appendResult.getId.getMessageId))
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 01/10: JAMES-3436 Email/set create: Support keywords
Posted by bt...@apache.org.
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 17d98a0bc52cd1372911efdbb60bc973129e17f4
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Oct 26 14:24:47 2020 +0700
JAMES-3436 Email/set create: Support keywords
---
.../rfc8621/contract/EmailSetMethodContract.scala | 64 +++++++++++++++++++++-
.../org/apache/james/jmap/mail/EmailSet.scala | 3 +-
.../apache/james/jmap/method/EmailSetMethod.scala | 1 +
3 files changed, 66 insertions(+), 2 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 0e8595b..6992bb6 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
@@ -223,12 +223,74 @@ trait EmailSetMethodContract {
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
.inPath(s"methodResponses[1][1].list")
+ .isEqualTo(s"""[{
+ | "mailboxIds": {
+ | "${mailboxId.serialize}": true
+ | },
+ | "subject": "Boredome comes from a boring mind!"
+ |}]""".stripMargin)
+ }
+
+ @Test
+ def createShouldSupportKeywords(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
+ | },
+ | "keywords": {
+ | "$$answered": true,
+ | "music": true
+ | }
+ | }
+ | }
+ | }, "c1"],
+ | ["Email/get",
+ | {
+ | "accountId": "$ACCOUNT_ID",
+ | "ids": ["#aaaaaa"],
+ | "properties": ["mailboxIds", "keywords"]
+ | },
+ | "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"""[{
| "mailboxIds": {
| "${mailboxId.serialize}": true
| },
- | "subject": "Boredome comes from a boring mind!"
+ | "keywords": {
+ | "$$answered": true,
+ | "music": true
+ | }
|}]""".stripMargin)
}
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 5985147..baedcf7 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
@@ -49,7 +49,8 @@ object EmailSet {
}
case class EmailCreationRequest(mailboxIds: MailboxIds,
- subject: Option[Subject]) {
+ subject: Option[Subject],
+ keywords: Option[Keywords]) {
def toMime4JMessage: Message = {
val builder = Message.Builder.of
subject.foreach(value => builder.setSubject(value.value))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetMethod.scala
index e95abb9..759cd30 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetMethod.scala
@@ -231,6 +231,7 @@ class EmailSetMethod @Inject()(serializer: EmailSetSerializer,
val appendResult = mailboxManager.getMailbox(mailboxId, mailboxSession)
.appendMessage(AppendCommand.builder()
.recent()
+ .withFlags(request.keywords.map(_.asFlags).getOrElse(new Flags()))
.build(request.toMime4JMessage),
mailboxSession)
CreationSuccess(clientId, EmailCreationResponse(appendResult.getId.getMessageId))
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org