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 aae1e1183385cfc7fbbf7bdb790cda9a8ae84771
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Wed Oct 30 13:23:56 2019 +0700

    JAMES-2944 wrapping by multipart/related when inline attachments
---
 .../jmap/draft/methods/MIMEMessageConverter.java   |  48 +++-
 .../draft/methods/MIMEMessageConverterTest.java    | 253 ++++++++++++---------
 2 files changed, 191 insertions(+), 110 deletions(-)

diff --git 
a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MIMEMessageConverter.java
 
b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MIMEMessageConverter.java
index 350a4aa..6057e1f 100644
--- 
a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MIMEMessageConverter.java
+++ 
b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MIMEMessageConverter.java
@@ -76,6 +76,7 @@ public class MIMEMessageConverter {
     private static final NameValuePair UTF_8_CHARSET = new 
NameValuePair("charset", StandardCharsets.UTF_8.name());
     private static final String ALTERNATIVE_SUB_TYPE = "alternative";
     private static final String MIXED_SUB_TYPE = "mixed";
+    private static final String RELATED_SUB_TYPE = "related";
     private static final String FIELD_PARAMETERS_SEPARATOR = ";";
     private static final String QUOTED_PRINTABLE = "quoted-printable";
     private static final String BASE64 = "base64";
@@ -178,7 +179,7 @@ public class MIMEMessageConverter {
         
Splitter.on(MessageFactory.JMAP_MULTIVALUED_FIELD_DELIMITER).split(multipleValues)
             .forEach(value -> addHeader(messageBuilder, fieldName, value));
     }
-    
+
     private void addHeader(Message.Builder messageBuilder, String fieldName, 
String value) {
         FieldParser<UnstructuredField> parser = UnstructuredFieldImpl.PARSER;
         RawField rawField = new RawField(fieldName, value);
@@ -204,13 +205,7 @@ public class MIMEMessageConverter {
     private Multipart createMultipart(CreationMessage newMessage, 
ImmutableList<MessageAttachment> messageAttachments) {
         try {
             if (hasAttachment(messageAttachments)) {
-                MultipartBuilder builder = 
MultipartBuilder.create(MIXED_SUB_TYPE);
-                addBody(newMessage, builder);
-    
-                Consumer<MessageAttachment> addAttachment = 
addAttachment(builder);
-                messageAttachments.forEach(addAttachment);
-    
-                return builder.build();
+                return createMultipartWithAttachments(newMessage, 
messageAttachments);
             } else {
                 return createMultipartAlternativeBody(newMessage);
             }
@@ -220,6 +215,43 @@ public class MIMEMessageConverter {
         }
     }
 
+    private Multipart createMultipartWithAttachments(CreationMessage 
newMessage, ImmutableList<MessageAttachment> messageAttachments) throws 
IOException {
+        MultipartBuilder mixedMultipartBuilder = 
MultipartBuilder.create(MIXED_SUB_TYPE);
+        List<MessageAttachment> inlineAttachments = messageAttachments.stream()
+            .filter(MessageAttachment::isInline)
+            .collect(Guavate.toImmutableList());
+        List<MessageAttachment> besideAttachments = messageAttachments.stream()
+            .filter(attachment -> !attachment.isInline())
+            .collect(Guavate.toImmutableList());
+
+        if (inlineAttachments.size() > 0) {
+            mixedMultipartBuilder.addBodyPart(relatedInnerMessage(newMessage, 
inlineAttachments));
+        } else {
+            addBody(newMessage, mixedMultipartBuilder);
+        }
+
+        addAttachments(besideAttachments, mixedMultipartBuilder);
+
+        return mixedMultipartBuilder.build();
+    }
+
+    private Message relatedInnerMessage(CreationMessage newMessage, 
List<MessageAttachment> inlines) throws IOException {
+        MultipartBuilder relatedMultipart = 
MultipartBuilder.create(RELATED_SUB_TYPE);
+        addBody(newMessage, relatedMultipart);
+
+        return Message.Builder.of()
+            .setBody(addAttachments(inlines, relatedMultipart)
+                .build())
+            .build();
+    }
+
+    private MultipartBuilder addAttachments(List<MessageAttachment> 
messageAttachments,
+                                            MultipartBuilder multipartBuilder) 
{
+        messageAttachments.forEach(addAttachment(multipartBuilder));
+
+        return multipartBuilder;
+    }
+    
     private void addBody(CreationMessage newMessage, MultipartBuilder builder) 
throws IOException {
         if (newMessage.getHtmlBody().isPresent() && 
newMessage.getTextBody().isPresent()) {
             Multipart body = createMultipartAlternativeBody(newMessage);
diff --git 
a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/MIMEMessageConverterTest.java
 
b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/MIMEMessageConverterTest.java
index 94966da..2b27933 100644
--- 
a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/MIMEMessageConverterTest.java
+++ 
b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/MIMEMessageConverterTest.java
@@ -45,7 +45,7 @@ import org.apache.james.mime4j.dom.address.Mailbox;
 import org.apache.james.mime4j.dom.field.ContentTypeField;
 import org.apache.james.mime4j.message.BasicBodyFactory;
 import org.apache.james.mime4j.stream.Field;
-import org.junit.jupiter.api.Disabled;
+import org.assertj.core.data.Index;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
@@ -582,46 +582,47 @@ class MIMEMessageConverterTest {
     class WithAttachments {
 
         @Test
-        void convertToMimeShouldAddAttachmentWhenOne() {
+        void convertToMimeShouldAddAttachment() {
             // Given
             MIMEMessageConverter sut = new MIMEMessageConverter();
 
             CreationMessage testMessage = CreationMessage.builder()
-                    .mailboxId("dead-bada55")
-                    .subject("subject")
-                    .from(DraftEmailer.builder().name("sender").build())
-                    .htmlBody("Hello <b>all<b>!")
-                    .build();
+                .mailboxId("dead-bada55")
+                .subject("subject")
+                .from(DraftEmailer.builder().name("sender").build())
+                .htmlBody("Hello <b>all<b>!")
+                .build();
 
             String expectedCID = "cid";
             String expectedMimeType = "image/png";
             String text = "123456";
             TextBody expectedBody = new 
BasicBodyFactory().textBody(text.getBytes(), StandardCharsets.UTF_8);
             MessageAttachment attachment = MessageAttachment.builder()
-                    
.attachment(org.apache.james.mailbox.model.Attachment.builder()
-                        .attachmentId(AttachmentId.from("blodId"))
-                        .bytes(text.getBytes())
-                        .type(expectedMimeType)
-                        .build())
-                    .cid(Cid.from(expectedCID))
-                    .isInline(true)
-                    .build();
+                .attachment(org.apache.james.mailbox.model.Attachment.builder()
+                    .attachmentId(AttachmentId.from("blodId"))
+                    .bytes(text.getBytes())
+                    .type(expectedMimeType)
+                    .build())
+                .cid(Cid.from(expectedCID))
+                .isInline(true)
+                .build();
 
             // When
             Message result = sut.convertToMime(new 
ValueWithId.CreationMessageEntry(
-                    CreationMessageId.of("user|mailbox|1"), testMessage), 
ImmutableList.of(attachment));
-
-            // Then
-            assertThat(result.getBody()).isInstanceOf(Multipart.class);
-            assertThat(result.isMultipart()).isTrue();
+                CreationMessageId.of("user|mailbox|1"), testMessage), 
ImmutableList.of(attachment));
             Multipart typedResult = (Multipart)result.getBody();
-            assertThat(typedResult.getBodyParts()).hasSize(2);
-            Entity attachmentPart = typedResult.getBodyParts().get(1);
-            
assertThat(attachmentPart.getBody()).isEqualToComparingOnlyGivenFields(expectedBody,
 "content");
-            
assertThat(attachmentPart.getDispositionType()).isEqualTo("inline");
-            
assertThat(attachmentPart.getMimeType()).isEqualTo(expectedMimeType);
-            
assertThat(attachmentPart.getHeader().getField("Content-ID").getBody()).isEqualTo(expectedCID);
-            
assertThat(attachmentPart.getContentTransferEncoding()).isEqualTo("base64");
+
+            assertThat(typedResult.getBodyParts())
+                .hasSize(1)
+                .extracting(entity -> (Multipart) entity.getBody())
+                .flatExtracting(Multipart::getBodyParts)
+                .anySatisfy(part -> {
+                    
assertThat(part.getBody()).isEqualToComparingOnlyGivenFields(expectedBody, 
"content");
+                    assertThat(part.getDispositionType()).isEqualTo("inline");
+                    assertThat(part.getMimeType()).isEqualTo(expectedMimeType);
+                    
assertThat(part.getHeader().getField("Content-ID").getBody()).isEqualTo(expectedCID);
+                    
assertThat(part.getContentTransferEncoding()).isEqualTo("base64");
+                });
         }
 
         @Test
@@ -630,12 +631,12 @@ class MIMEMessageConverterTest {
             MIMEMessageConverter sut = new MIMEMessageConverter();
 
             CreationMessage testMessage = CreationMessage.builder()
-                    .mailboxId("dead-bada55")
-                    .subject("subject")
-                    .from(DraftEmailer.builder().name("sender").build())
-                    .textBody("Hello all!")
-                    .htmlBody("Hello <b>all<b>!")
-                    .build();
+                .mailboxId("dead-bada55")
+                .subject("subject")
+                .from(DraftEmailer.builder().name("sender").build())
+                .textBody("Hello all!")
+                .htmlBody("Hello <b>all<b>!")
+                .build();
             TextBody expectedTextBody = new BasicBodyFactory().textBody("Hello 
all!".getBytes(), StandardCharsets.UTF_8);
             TextBody expectedHtmlBody = new BasicBodyFactory().textBody("Hello 
<b>all<b>!".getBytes(), StandardCharsets.UTF_8);
 
@@ -644,39 +645,40 @@ class MIMEMessageConverterTest {
             String text = "123456";
             TextBody expectedAttachmentBody = new 
BasicBodyFactory().textBody(text.getBytes(), StandardCharsets.UTF_8);
             MessageAttachment attachment = MessageAttachment.builder()
-                    
.attachment(org.apache.james.mailbox.model.Attachment.builder()
-                        .attachmentId(AttachmentId.from("blodId"))
-                        .bytes(text.getBytes())
-                        .type(expectedMimeType)
-                        .build())
-                    .cid(Cid.from(expectedCID))
-                    .isInline(true)
-                    .build();
+                .attachment(org.apache.james.mailbox.model.Attachment.builder()
+                    .attachmentId(AttachmentId.from("blodId"))
+                    .bytes(text.getBytes())
+                    .type(expectedMimeType)
+                    .build())
+                .cid(Cid.from(expectedCID))
+                .isInline(true)
+                .build();
 
             // When
             Message result = sut.convertToMime(new 
ValueWithId.CreationMessageEntry(
-                    CreationMessageId.of("user|mailbox|1"), testMessage), 
ImmutableList.of(attachment));
-
-            // Then
-            assertThat(result.getBody()).isInstanceOf(Multipart.class);
-            assertThat(result.isMultipart()).isTrue();
+                CreationMessageId.of("user|mailbox|1"), testMessage), 
ImmutableList.of(attachment));
             Multipart typedResult = (Multipart)result.getBody();
-            assertThat(typedResult.getBodyParts()).hasSize(2);
-            Entity mainBodyPart = typedResult.getBodyParts().get(0);
-            assertThat(mainBodyPart.getBody()).isInstanceOf(Multipart.class);
-            assertThat(mainBodyPart.isMultipart()).isTrue();
-            
assertThat(mainBodyPart.getMimeType()).isEqualTo("multipart/alternative");
-            
assertThat(((Multipart)mainBodyPart.getBody()).getBodyParts()).hasSize(2);
-            Entity textPart = 
((Multipart)mainBodyPart.getBody()).getBodyParts().get(0);
-            Entity htmlPart = 
((Multipart)mainBodyPart.getBody()).getBodyParts().get(1);
-            
assertThat(textPart.getBody()).isEqualToComparingOnlyGivenFields(expectedTextBody,
 "content");
-            
assertThat(htmlPart.getBody()).isEqualToComparingOnlyGivenFields(expectedHtmlBody,
 "content");
-
-            Entity attachmentPart = typedResult.getBodyParts().get(1);
-            
assertThat(attachmentPart.getBody()).isEqualToComparingOnlyGivenFields(expectedAttachmentBody,
 "content");
-            
assertThat(attachmentPart.getDispositionType()).isEqualTo("inline");
-            
assertThat(attachmentPart.getMimeType()).isEqualTo(expectedMimeType);
-            
assertThat(attachmentPart.getHeader().getField("Content-ID").getBody()).isEqualTo(expectedCID);
+
+            assertThat(typedResult.getBodyParts())
+                .hasSize(1)
+                .extracting(entity -> (Multipart) entity.getBody())
+                .flatExtracting(Multipart::getBodyParts)
+                .satisfies(part -> {
+                    assertThat(part.getBody()).isInstanceOf(Multipart.class);
+                    assertThat(part.isMultipart()).isTrue();
+                    
assertThat(part.getMimeType()).isEqualTo("multipart/alternative");
+                    
assertThat(((Multipart)part.getBody()).getBodyParts()).hasSize(2);
+                    Entity textPart = 
((Multipart)part.getBody()).getBodyParts().get(0);
+                    Entity htmlPart = 
((Multipart)part.getBody()).getBodyParts().get(1);
+                    
assertThat(textPart.getBody()).isEqualToComparingOnlyGivenFields(expectedTextBody,
 "content");
+                    
assertThat(htmlPart.getBody()).isEqualToComparingOnlyGivenFields(expectedHtmlBody,
 "content");
+                }, Index.atIndex(0))
+                .satisfies(part -> {
+                    
assertThat(part.getBody()).isEqualToComparingOnlyGivenFields(expectedAttachmentBody,
 "content");
+                    assertThat(part.getDispositionType()).isEqualTo("inline");
+                    assertThat(part.getMimeType()).isEqualTo(expectedMimeType);
+                    
assertThat(part.getHeader().getField("Content-ID").getBody()).isEqualTo(expectedCID);
+                }, Index.atIndex(1));
         }
 
         @Test
@@ -709,11 +711,11 @@ class MIMEMessageConverterTest {
             MIMEMessageConverter sut = new MIMEMessageConverter();
 
             CreationMessage testMessage = CreationMessage.builder()
-                    .mailboxIds(ImmutableList.of("dead-bada55"))
-                    .subject("subject")
-                    .from(DraftEmailer.builder().name("sender").build())
-                    .htmlBody("Hello <b>all<b>!")
-                    .build();
+                .mailboxIds(ImmutableList.of("dead-bada55"))
+                .subject("subject")
+                .from(DraftEmailer.builder().name("sender").build())
+                .htmlBody("Hello <b>all<b>!")
+                .build();
 
             String expectedCID = "cid";
             String expectedMimeType = "image/png";
@@ -721,29 +723,26 @@ class MIMEMessageConverterTest {
             String name = "ديناصور.png";
             String expectedName = EncoderUtil.encodeEncodedWord(name, 
Usage.TEXT_TOKEN);
             MessageAttachment attachment = MessageAttachment.builder()
-                    .name(name)
-                    
.attachment(org.apache.james.mailbox.model.Attachment.builder()
-                        .attachmentId(AttachmentId.from("blodId"))
-                        .bytes(text.getBytes())
-                        .type(expectedMimeType)
-                        .build())
-                    .cid(Cid.from(expectedCID))
-                    .isInline(true)
-                    .build();
+                .name(name)
+                .attachment(org.apache.james.mailbox.model.Attachment.builder()
+                    .attachmentId(AttachmentId.from("blodId"))
+                    .bytes(text.getBytes())
+                    .type(expectedMimeType)
+                    .build())
+                .cid(Cid.from(expectedCID))
+                .isInline(true)
+                .build();
 
             // When
             Message result = sut.convertToMime(new 
ValueWithId.CreationMessageEntry(
-                    CreationMessageId.of("user|mailbox|1"), testMessage), 
ImmutableList.of(attachment));
-
-            // Then
-            assertThat(result.getBody()).isInstanceOf(Multipart.class);
-            assertThat(result.isMultipart()).isTrue();
+                CreationMessageId.of("user|mailbox|1"), testMessage), 
ImmutableList.of(attachment));
             Multipart typedResult = (Multipart)result.getBody();
-            assertThat(typedResult.getBodyParts()).hasSize(2);
 
-            Entity attachmentPart = typedResult.getBodyParts().get(1);
-            String filename = getNameParameterValue(attachmentPart);
-            assertThat(filename).isEqualTo(expectedName);
+            assertThat(typedResult.getBodyParts())
+                .hasSize(1)
+                .extracting(entity -> (Multipart) entity.getBody())
+                .flatExtracting(Multipart::getBodyParts)
+                .anySatisfy(part -> 
assertThat(getNameParameterValue(part)).isEqualTo(expectedName));
         }
 
 
@@ -808,7 +807,7 @@ class MIMEMessageConverterTest {
         }
 
         @Test
-        void convertToMimeShouldNotHaveChildrenAttachmentParts() {
+        void convertToMimeShouldHaveChildrenAttachmentParts() {
             MIMEMessageConverter sut = new MIMEMessageConverter();
 
             CreationMessage testMessage = CreationMessage.builder()
@@ -838,29 +837,28 @@ class MIMEMessageConverterTest {
                 .anySatisfy(contentDisposition -> 
assertThat(contentDisposition).isEqualTo("attachment"));
         }
 
-        @Disabled("Current structure is mixed -> alternative, attachments")
         @Test
-        void convertToMimeShouldHaveChildMultipartWhenInline() {
+        void convertToMimeShouldHaveChildMultipartWhenOnlyInline() {
             MIMEMessageConverter sut = new MIMEMessageConverter();
 
             CreationMessage testMessage = CreationMessage.builder()
-                    .mailboxIds(ImmutableList.of("dead-bada55"))
-                    .subject("subject")
-                    .from(DraftEmailer.builder().name("sender").build())
-                    .htmlBody("Hello <b>all<b>!")
-                    .build();
+                .mailboxIds(ImmutableList.of("dead-bada55"))
+                .subject("subject")
+                .from(DraftEmailer.builder().name("sender").build())
+                .htmlBody("Hello <b>all<b>!")
+                .build();
 
             String name = "ديناصور.png";
             MessageAttachment attachment = MessageAttachment.builder()
-                    .name(name)
-                    
.attachment(org.apache.james.mailbox.model.Attachment.builder()
-                        .attachmentId(AttachmentId.from("blodId"))
-                        .bytes("123456".getBytes())
-                        .type("image/png")
-                        .build())
-                    .cid(Cid.from("cid"))
-                    .isInline(true)
-                    .build();
+                .name(name)
+                .attachment(org.apache.james.mailbox.model.Attachment.builder()
+                    .attachmentId(AttachmentId.from("blodId"))
+                    .bytes("123456".getBytes())
+                    .type("image/png")
+                    .build())
+                .cid(Cid.from("cid"))
+                .isInline(true)
+                .build();
 
             Message result = sut.convertToMime(new 
ValueWithId.CreationMessageEntry(
                     CreationMessageId.of("user|mailbox|1"), testMessage), 
ImmutableList.of(attachment));
@@ -874,6 +872,57 @@ class MIMEMessageConverterTest {
                 .allSatisfy(subType -> 
assertThat(subType).isEqualTo("related"));
         }
 
+        @Test
+        void 
convertToMimeShouldHaveChildMultipartWhenBothInlinesAndAttachments() {
+            MIMEMessageConverter sut = new MIMEMessageConverter();
+
+            CreationMessage testMessage = CreationMessage.builder()
+                .mailboxIds(ImmutableList.of("dead-bada55"))
+                .subject("subject")
+                .from(DraftEmailer.builder().name("sender").build())
+                .htmlBody("Hello <b>all<b>!")
+                .build();
+
+            MessageAttachment inline = MessageAttachment.builder()
+                .name("ديناصور.png")
+                .attachment(org.apache.james.mailbox.model.Attachment.builder()
+                    .attachmentId(AttachmentId.from("blodId"))
+                    .bytes("inline data".getBytes())
+                    .type("image/png")
+                    .build())
+                .cid(Cid.from("cid"))
+                .isInline(true)
+                .build();
+
+            MessageAttachment attachment = MessageAttachment.builder()
+                .name("att.pdf")
+                .attachment(org.apache.james.mailbox.model.Attachment.builder()
+                    .attachmentId(AttachmentId.from("blodId2"))
+                    .bytes("attachment data".getBytes())
+                    .type("image/png")
+                    .build())
+                .cid(Cid.from("cid2"))
+                .isInline(false)
+                .build();
+
+            Message result = sut.convertToMime(new 
ValueWithId.CreationMessageEntry(
+                    CreationMessageId.of("user|mailbox|1"), testMessage), 
ImmutableList.of(inline, attachment));
+            Multipart typedResult = (Multipart)result.getBody();
+
+            assertThat(typedResult.getBodyParts())
+                .hasSize(2)
+                .satisfies(part -> {
+                    Multipart multipartRelated = (Multipart) part.getBody();
+                    
assertThat(multipartRelated.getSubType()).isEqualTo("related");
+                    assertThat(multipartRelated.getBodyParts())
+                        .extracting(Entity::getDispositionType)
+                        .contains("inline");
+                }, Index.atIndex(0))
+                .satisfies(part -> {
+                    
assertThat(part.getDispositionType()).isEqualTo("attachment");
+                }, Index.atIndex(1));
+        }
+
         private String getNameParameterValue(Entity attachmentPart) {
             return ((ContentTypeField) 
attachmentPart.getHeader().getField("Content-Type")).getParameter("name");
         }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org
For additional commands, e-mail: server-dev-h...@james.apache.org

Reply via email to