You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2020/11/17 03:37:21 UTC
[james-project] 02/06: JAMES-3447 Email/set create should return
blobId, threadId, size
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit bedde56801279f29aaf08db2fab1a0103e2fa427
Author: LanKhuat <dl...@linagora.com>
AuthorDate: Mon Nov 16 16:01:50 2020 +0700
JAMES-3447 Email/set create should return blobId, threadId, size
---
.../org/apache/james/mailbox/MessageManager.java | 8 +-
.../james/mailbox/store/StoreMessageManager.java | 2 +-
.../methods/SetMessagesCreationProcessorTest.java | 3 +-
.../methods/SetMessagesUpdateProcessorTest.java | 3 +-
.../rfc8621/contract/EmailSetMethodContract.scala | 823 +++++++++++++--------
.../james/jmap/json/EmailSetSerializer.scala | 2 +-
.../scala/org/apache/james/jmap/mail/Email.scala | 2 +-
.../org/apache/james/jmap/mail/EmailSet.scala | 3 +-
.../jmap/method/EmailSetCreatePerformer.scala | 6 +-
9 files changed, 522 insertions(+), 330 deletions(-)
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
index 779d84e..c5e8512 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
@@ -147,10 +147,12 @@ public interface MessageManager {
class AppendResult {
private final ComposedMessageId id;
+ private final Long size;
private final Optional<List<MessageAttachmentMetadata>> messageAttachments;
- public AppendResult(ComposedMessageId id, Optional<List<MessageAttachmentMetadata>> messageAttachments) {
+ public AppendResult(ComposedMessageId id, Long size, Optional<List<MessageAttachmentMetadata>> messageAttachments) {
this.id = id;
+ this.size = size;
this.messageAttachments = messageAttachments;
}
@@ -158,6 +160,10 @@ public interface MessageManager {
return id;
}
+ public Long getSize() {
+ return size;
+ }
+
public List<MessageAttachmentMetadata> getMessageAttachments() {
Preconditions.checkState(messageAttachments.isPresent(), "'attachment storage' not supported by the implementation");
return messageAttachments.get();
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
index 0103598..a1edc78 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
@@ -450,7 +450,7 @@ public class StoreMessageManager implements MessageManager {
.block();
MessageMetaData messageMetaData = data.getLeft();
ComposedMessageId ids = new ComposedMessageId(mailbox.getMailboxId(), messageMetaData.getMessageId(), messageMetaData.getUid());
- return new AppendResult(ids, data.getRight());
+ return new AppendResult(ids, messageMetaData.getSize(), data.getRight());
}, MailboxPathLocker.LockType.Write);
}
}
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessorTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessorTest.java
index 453f932..6e4c162 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessorTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessorTest.java
@@ -102,6 +102,7 @@ public class SetMessagesCreationProcessorTest {
private static final InMemoryId OUTBOX_ID = InMemoryId.of(12345);
private static final String DRAFTS = "drafts";
private static final InMemoryId DRAFTS_ID = InMemoryId.of(12);
+ private static final Long TEST_MESSAGE_SIZE = 1L;
private final CreationMessage.Builder creationMessageBuilder = CreationMessage.builder()
.from(DraftEmailer.builder().name("alice").email("alice@example.com").build())
@@ -194,7 +195,7 @@ public class SetMessagesCreationProcessorTest {
when(outbox.getMailboxPath()).thenReturn(MailboxPath.forUser(USER, OUTBOX));
when(outbox.appendMessage(any(MessageManager.AppendCommand.class), any(MailboxSession.class)))
- .thenReturn(new MessageManager.AppendResult(new ComposedMessageId(OUTBOX_ID, TestMessageId.of(23), MessageUid.of(1)),
+ .thenReturn(new MessageManager.AppendResult(new ComposedMessageId(OUTBOX_ID, TestMessageId.of(23), MessageUid.of(1)), TEST_MESSAGE_SIZE,
Optional.of(ImmutableList.of())));
drafts = mock(MessageManager.class);
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessorTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessorTest.java
index b33f25c..5ce3a4b 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessorTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessorTest.java
@@ -92,6 +92,7 @@ public class SetMessagesUpdateProcessorTest {
private static final InMemoryId OUTBOX_ID = InMemoryId.of(12345);
private static final String DRAFTS = "drafts";
private static final InMemoryId DRAFTS_ID = InMemoryId.of(12);
+ private static final Long TEST_MESSAGE_SIZE = 1L;
public static class TestSystemMailboxesProvider implements SystemMailboxesProvider {
@@ -200,7 +201,7 @@ public class SetMessagesUpdateProcessorTest {
when(outbox.appendMessage(any(MessageManager.AppendCommand.class), any(MailboxSession.class)))
.thenReturn(new MessageManager.AppendResult(
- new ComposedMessageId(OUTBOX_ID, TestMessageId.of(23), MessageUid.of(1)),
+ new ComposedMessageId(OUTBOX_ID, TestMessageId.of(23), MessageUid.of(1)), TEST_MESSAGE_SIZE,
Optional.empty()));
drafts = mock(MessageManager.class);
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 38bfb79..b843fed 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
@@ -49,7 +49,7 @@ import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.{BeforeEach, Test}
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
-import play.api.libs.json.{JsString, Json}
+import play.api.libs.json.{JsNumber, JsString, Json}
import scala.jdk.CollectionConverters._
@@ -186,10 +186,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val createResponse = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = createResponse
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = createResponse
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -475,10 +493,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val responseAsJson = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -535,10 +571,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val responseAsJson = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -592,10 +646,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val responseAsJson = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -648,10 +720,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val createResponse = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = createResponse
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = createResponse
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -709,10 +799,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val createResponse = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = createResponse
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = createResponse
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -767,10 +875,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val createResponse = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = createResponse
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = createResponse
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -826,10 +952,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val responseAsJson = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -1162,10 +1306,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val responseAsJson = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -1241,10 +1403,28 @@ trait EmailSetMethodContract {
.body
.asString
+ val responseAsJson = Json.parse(response)
+ .\("methodResponses")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
+ .\("id")
+ .get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
.inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -1794,20 +1974,28 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val blobIdToDownload = Json.parse(response)
+ val responseAsJson = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
- .\("attachments")
- .\(0)
- .\("blobId")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
+ .\("id")
.get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
+ assertThatJson(response)
+ .inPath("methodResponses[0][1].created.aaaaaa")
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -1821,7 +2009,7 @@ trait EmailSetMethodContract {
| "attachments": [
| {
| "partId": "5",
- | "blobId": "$blobIdToDownload",
+ | "blobId": "${messageId}_5",
| "size": 11,
| "type": "text/plain",
| "charset": "UTF-8",
@@ -1836,7 +2024,7 @@ trait EmailSetMethodContract {
.basePath("")
.header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
.when
- .get(s"/download/$accountId/$blobIdToDownload")
+ .get(s"/download/$accountId/${messageId}_5")
.`then`
.statusCode(SC_OK)
.contentType("text/plain")
@@ -1929,18 +2117,28 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val messageId = Json.parse(response)
+ val responseAsJson = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
.\("id")
.get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
+ assertThatJson(response)
+ .inPath("methodResponses[0][1].created.aaaaaa")
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -2075,18 +2273,28 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val messageId = Json.parse(response)
+ val responseAsJson = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
.\("id")
.get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
+ assertThatJson(response)
+ .inPath("methodResponses[0][1].created.aaaaaa")
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.whenIgnoringPaths("methodResponses[1][1].list[0].id")
@@ -2239,79 +2447,59 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val messageId = Json.parse(response)
+ val responseAsJson = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
.\("id")
.get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
assertThatJson(response)
+ .inPath(s"methodResponses[1][1].list[0]")
.isEqualTo(
s"""{
- | "sessionState": "75128aab4b1b",
- | "methodResponses": [
- | ["Email/set", {
- | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
- | "newState": "000001",
- | "created": {
- | "aaaaaa": {
- | "id": "$messageId"
- | }
- | }
- | }, "c1"],
- | ["Email/get", {
- | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
- | "state": "000001",
- | "list": [
- | {
- | "id": "$messageId",
- | "bodyStructure": {
- | "type": "multipart/mixed",
+ | "id": "$messageId",
+ | "bodyStructure": {
+ | "type": "multipart/mixed",
+ | "subParts": [
+ | {
+ | "type": "multipart/related",
+ | "subParts": [
+ | {
+ | "type": "multipart/alternative",
| "subParts": [
| {
- | "type": "multipart/related",
- | "subParts": [
- | {
- | "type": "multipart/alternative",
- | "subParts": [
- | {
- | "type": "text/html"
- | },
- | {
- | "type": "text/plain"
- | }
- | ]
- | },
- | {
- | "type": "text/plain",
- | "disposition": "inline",
- | "cid": "abc"
- | },
- | {
- | "type": "text/plain",
- | "disposition": "inline",
- | "cid": "def"
- | }
- | ]
+ | "type": "text/html"
| },
| {
- | "type": "text/plain",
- | "disposition": "attachment"
+ | "type": "text/plain"
| }
| ]
+ | },
+ | {
+ | "type": "text/plain",
+ | "disposition": "inline",
+ | "cid": "abc"
+ | },
+ | {
+ | "type": "text/plain",
+ | "disposition": "inline",
+ | "cid": "def"
| }
- | }
- | ],
- | "notFound": []
- | }, "c2"]
- | ]
+ | ]
+ | },
+ | {
+ | "type": "text/plain",
+ | "disposition": "attachment"
+ | }
+ | ]
+ | }
|}""".stripMargin)
}
@@ -2396,64 +2584,54 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val messageId = Json.parse(response)
+ val responseAsJson = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
.\("id")
.get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
assertThatJson(response)
+ .inPath("methodResponses[0][1].created.aaaaaa")
.isEqualTo(
s"""{
- | "sessionState": "75128aab4b1b",
- | "methodResponses": [
- | ["Email/set", {
- | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
- | "newState": "000001",
- | "created": {
- | "aaaaaa": {
- | "id": "$messageId"
- | }
- | }
- | }, "c1"],
- | ["Email/get", {
- | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
- | "state": "000001",
- | "list": [
- | {
- | "id": "$messageId",
- | "bodyStructure": {
- | "type": "multipart/mixed",
- | "subParts": [
- | {
- | "type":"multipart/alternative",
- | "subParts": [
- | {
- | "type":"text/html"
- | },
- | {
- | "type":"text/plain"
- | }
- | ]
- | },
- | {
- | "type": "text/plain",
- | "disposition": "attachment"
- | }
- | ]
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
+
+ assertThatJson(response)
+ .inPath(s"methodResponses[1][1].list[0]")
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "bodyStructure": {
+ | "type": "multipart/mixed",
+ | "subParts": [
+ | {
+ | "type":"multipart/alternative",
+ | "subParts": [
+ | {
+ | "type":"text/html"
+ | },
+ | {
+ | "type":"text/plain"
| }
- | }
- | ],
- | "notFound": []
- | }, "c2"]
- | ]
+ | ]
+ | },
+ | {
+ | "type": "text/plain",
+ | "disposition": "attachment"
+ | }
+ | ]
+ | }
|}""".stripMargin)
}
@@ -2546,70 +2724,60 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val messageId = Json.parse(response)
+ val responseAsJson = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
.\("id")
.get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
assertThatJson(response)
+ .inPath("methodResponses[0][1].created.aaaaaa")
.isEqualTo(
s"""{
- | "sessionState": "75128aab4b1b",
- | "methodResponses": [
- | ["Email/set", {
- | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
- | "newState": "000001",
- | "created": {
- | "aaaaaa": {
- | "id": "$messageId"
- | }
- | }
- | }, "c1"],
- | ["Email/get", {
- | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
- | "state": "000001",
- | "list": [
- | {
- | "id": "$messageId",
- | "bodyStructure": {
- | "type": "multipart/related",
- | "subParts": [
- | {
- | "type":"multipart/alternative",
- | "subParts": [
- | {
- | "type":"text/html"
- | },
- | {
- | "type":"text/plain"
- | }
- | ]
- | },
- | {
- | "type": "text/plain",
- | "disposition": "inline",
- | "cid": "abc"
- | },
- | {
- | "type": "text/plain",
- | "disposition": "inline",
- | "cid": "def"
- | }
- | ]
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
+
+ assertThatJson(response)
+ .inPath(s"methodResponses[1][1].list[0]")
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "bodyStructure": {
+ | "type": "multipart/related",
+ | "subParts": [
+ | {
+ | "type":"multipart/alternative",
+ | "subParts": [
+ | {
+ | "type":"text/html"
+ | },
+ | {
+ | "type":"text/plain"
| }
- | }
- | ],
- | "notFound": []
- | }, "c2"]
- | ]
+ | ]
+ | },
+ | {
+ | "type": "text/plain",
+ | "disposition": "inline",
+ | "cid": "abc"
+ | },
+ | {
+ | "type": "text/plain",
+ | "disposition": "inline",
+ | "cid": "def"
+ | }
+ | ]
+ | }
|}""".stripMargin)
}
@@ -2685,18 +2853,28 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val messageId = Json.parse(response)
+ val responseAsJson = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
.\("id")
.get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
+
+ assertThatJson(response)
+ .inPath("methodResponses[0][1].created.aaaaaa")
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
assertThatJson(response)
.isEqualTo(
@@ -2708,7 +2886,10 @@ trait EmailSetMethodContract {
| "newState": "000001",
| "created": {
| "aaaaaa": {
- | "id": "$messageId"
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
| }
| }
| }, "c1"],
@@ -2794,18 +2975,18 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val messageId = Json.parse(response)
+ val responseAsJson = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
.\("id")
.get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
assertThatJson(response)
.isEqualTo(
@@ -2817,7 +2998,10 @@ trait EmailSetMethodContract {
| "newState": "000001",
| "created": {
| "aaaaaa": {
- | "id": "$messageId"
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
| }
| }
| }, "c1"],
@@ -2956,80 +3140,69 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val messageId = Json.parse(response)
+ val createResponse = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = createResponse
.\("id")
.get.asInstanceOf[JsString].value
+ val size = createResponse
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
+ .inPath("methodResponses[0][1].created.aaaaaa")
.isEqualTo(
s"""{
- | "sessionState": "75128aab4b1b",
- | "methodResponses": [
- | ["Email/set", {
- | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
- | "newState": "000001",
- | "created": {
- | "aaaaaa": {
- | "id": "$messageId"
- | }
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
+
+ assertThatJson(response)
+ .inPath(s"methodResponses[1][1].list[0]")
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
+ | "bodyStructure": {
+ | "type": "multipart/mixed",
+ | "subParts": [
+ | {
+ | "type": "multipart/related",
+ | "subParts": [
+ | {
+ | "type": "multipart/alternative",
+ | "subParts": [
+ | {
+ | "type": "text/html"
+ | },
+ | {
+ | "type": "text/plain"
+ | }
+ | ]
+ | },
+ | {
+ | "type": "text/plain",
+ | "disposition": "inline",
+ | "cid": "abc"
+ | },
+ | {
+ | "type": "text/plain",
+ | "disposition": "inline",
+ | "cid": "def"
+ | }
+ | ]
+ | },
+ | {
+ | "type": "text/plain",
+ | "disposition": "attachment"
| }
- | }, "c1"],
- | ["Email/get", {
- | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
- | "state": "000001",
- | "list": [
- | {
- | "id": "$messageId",
- | "bodyStructure": {
- | "type": "multipart/mixed",
- | "subParts": [
- | {
- | "type": "multipart/related",
- | "subParts": [
- | {
- | "type": "multipart/alternative",
- | "subParts": [
- | {
- | "type": "text/html"
- | },
- | {
- | "type": "text/plain"
- | }
- | ]
- | },
- | {
- | "type": "text/plain",
- | "disposition": "inline",
- | "cid": "abc"
- | },
- | {
- | "type": "text/plain",
- | "disposition": "inline",
- | "cid": "def"
- | }
- | ]
- | },
- | {
- | "type": "text/plain",
- | "disposition": "attachment"
- | }
- | ]
- | }
- | }
- | ],
- | "notFound": []
- | }, "c2"]
- | ]
+ | ]
+ | }
|}""".stripMargin)
}
@@ -3103,26 +3276,34 @@ trait EmailSetMethodContract {
.body
.asString
- assertThatJson(response)
- .whenIgnoringPaths("methodResponses[0][1].created.aaaaaa.id")
- .inPath("methodResponses[0][1].created.aaaaaa")
- .isEqualTo("{}".stripMargin)
-
- val blobIdToDownload = Json.parse(response)
+ val responseAsJson = Json.parse(response)
.\("methodResponses")
- .\(1).\(1)
- .\("list")
- .\(0)
- .\("attachments")
- .\(0)
- .\("blobId")
+ .\(0).\(1)
+ .\("created")
+ .\("aaaaaa")
+
+ val messageId = responseAsJson
+ .\("id")
.get.asInstanceOf[JsString].value
+ val size = responseAsJson
+ .\("size")
+ .get.asInstanceOf[JsNumber].value
assertThatJson(response)
- .whenIgnoringPaths("methodResponses[1][1].list[0].id")
- .inPath(s"methodResponses[1][1].list")
+ .inPath("methodResponses[0][1].created.aaaaaa")
.isEqualTo(
- s"""[{
+ s"""{
+ | "id": "$messageId",
+ | "blobId": "$messageId",
+ | "threadId": "$messageId",
+ | "size": $size
+ |}""".stripMargin)
+
+ assertThatJson(response)
+ .inPath(s"methodResponses[1][1].list[0]")
+ .isEqualTo(
+ s"""{
+ | "id": "$messageId",
| "mailboxIds": {
| "${mailboxId.serialize}": true
| },
@@ -3131,7 +3312,7 @@ trait EmailSetMethodContract {
| {
| "name": "myAttachment",
| "partId": "5",
- | "blobId": "$blobIdToDownload",
+ | "blobId": "${messageId}_5",
| "size": 11,
| "type": "text/plain",
| "charset": "UTF-8",
@@ -3140,7 +3321,7 @@ trait EmailSetMethodContract {
| "location": "http://125.26.23.36/content"
| }
| ]
- |}]""".stripMargin)
+ |}""".stripMargin)
}
@Test
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 6ebc2c6..accb3fb 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
@@ -202,6 +202,7 @@ class EmailSetSerializer @Inject()(messageIdFactory: MessageId.Factory, mailboxI
keywordsMap => STRICT_KEYWORDS_FACTORY.fromSet(keywordsMap.keys.toSet)
.fold(e => JsError(e.getMessage), keywords => JsSuccess(keywords)))
+ private implicit val blobIdFormat: Format[BlobId] = Json.valueFormat[BlobId]
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](_.value, setErrorWrites)
@@ -339,7 +340,6 @@ class EmailSetSerializer @Inject()(messageIdFactory: MessageId.Factory, mailboxI
case AsGroupedAddresses => GroupedAddressReads
}
- private implicit val blobIdReads: Reads[BlobId] = Json.valueReads[BlobId]
private implicit val nameReads: Reads[Name] = Json.valueReads[Name]
private implicit val charsetReads: Reads[Charset] = Json.valueReads[Charset]
private implicit val dispositionReads: Reads[Disposition] = Json.valueReads[Disposition]
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 534b1ec..23fd436 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
@@ -82,7 +82,7 @@ object Email {
type Size = Long Refined NonNegative
val Zero: Size = 0L
- private[mail] def sanitizeSize(value: Long): Size = {
+ def sanitizeSize(value: Long): Size = {
val size: Either[String, Size] = refineV[NonNegative](value)
size.fold(e => {
logger.error(s"Encountered an invalid Email size: $e")
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 ca1af42..dab3d2c 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
@@ -32,6 +32,7 @@ import org.apache.james.jmap.core.Id.Id
import org.apache.james.jmap.core.State.State
import org.apache.james.jmap.core.{AccountId, SetError, UTCDate}
import org.apache.james.jmap.mail.Disposition.INLINE
+import org.apache.james.jmap.mail.Email.Size
import org.apache.james.jmap.mail.EmailSet.{EmailCreationId, UnparsedMessageId}
import org.apache.james.jmap.method.WithAccountId
import org.apache.james.mailbox.exception.AttachmentNotFoundException
@@ -394,5 +395,5 @@ case class InvalidEmailPropertyException(property: String, cause: String) extend
case class InvalidEmailUpdateException(property: String, cause: String) extends EmailUpdateValidationException
-case class EmailCreationResponse(id: MessageId)
+case class EmailCreationResponse(id: MessageId, blobId: Option[BlobId], threadId: Option[BlobId], size: Size)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetCreatePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetCreatePerformer.scala
index 662c750..0bc684f 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetCreatePerformer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetCreatePerformer.scala
@@ -29,7 +29,7 @@ import org.apache.james.jmap.core.SetError.SetErrorDescription
import org.apache.james.jmap.core.{Properties, SetError, UTCDate}
import org.apache.james.jmap.json.EmailSetSerializer
import org.apache.james.jmap.mail.EmailSet.EmailCreationId
-import org.apache.james.jmap.mail.{EmailCreationRequest, EmailCreationResponse, EmailSetRequest}
+import org.apache.james.jmap.mail.{BlobId, Email, EmailCreationRequest, EmailCreationResponse, EmailSetRequest}
import org.apache.james.jmap.method.EmailSetCreatePerformer.{CreationFailure, CreationResult, CreationResults, CreationSuccess}
import org.apache.james.mailbox.MessageManager.AppendCommand
import org.apache.james.mailbox.exception.{AttachmentNotFoundException, MailboxNotFoundException}
@@ -99,7 +99,9 @@ class EmailSetCreatePerformer @Inject()(serializer: EmailSetSerializer,
.withInternalDate(Date.from(request.receivedAt.getOrElse(UTCDate(ZonedDateTime.now())).asUTC.toInstant))
.build(message),
mailboxSession)
- CreationSuccess(clientId, EmailCreationResponse(appendResult.getId.getMessageId))
+
+ val blobId: Option[BlobId] = BlobId.of(appendResult.getId.getMessageId).toOption
+ CreationSuccess(clientId, EmailCreationResponse(appendResult.getId.getMessageId, blobId, blobId, Email.sanitizeSize(appendResult.getSize)))
})
.subscribeOn(Schedulers.elastic())
.onErrorResume(e => SMono.just[CreationResult](CreationFailure(clientId, e))))
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org