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 d1a8c287a7c6264afeeaa12c336d4d5e342b30b0 Author: Rene Cordier <[email protected]> AuthorDate: Thu Nov 21 17:45:56 2019 +0700 JAMES-2987 Add MessageHeaderViewFactory --- .../jmap/draft/methods/MIMEMessageConverter.java | 4 +- .../model/message/view/MessageFullViewFactory.java | 86 +------------ .../model/message/view/MessageHeaderView.java | 2 +- .../message/view/MessageHeaderViewFactory.java | 94 ++++++++++++++ .../model/message/view/MessageViewFactory.java | 72 +++++++++++ .../message/view/MessageHeaderViewFactoryTest.java | 141 +++++++++++++++++++++ .../jmap-draft/src/test/resources/fullMessage.eml | 60 +++++++++ 7 files changed, 376 insertions(+), 83 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 c9e3dcd..eac8c13 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 @@ -31,7 +31,7 @@ import java.util.stream.Collectors; import org.apache.james.jmap.draft.model.CreationMessage; import org.apache.james.jmap.draft.model.CreationMessage.DraftEmailer; -import org.apache.james.jmap.draft.model.message.view.MessageFullViewFactory; +import org.apache.james.jmap.draft.model.message.view.MessageViewFactory; import org.apache.james.mailbox.model.MessageAttachment; import org.apache.james.mime4j.codec.DecodeMonitor; import org.apache.james.mime4j.codec.EncoderUtil; @@ -176,7 +176,7 @@ public class MIMEMessageConverter { } private void addMultivaluedHeader(Message.Builder messageBuilder, String fieldName, String multipleValues) { - Splitter.on(MessageFullViewFactory.JMAP_MULTIVALUED_FIELD_DELIMITER).split(multipleValues) + Splitter.on(MessageViewFactory.JMAP_MULTIVALUED_FIELD_DELIMITER).split(multipleValues) .forEach(value -> addHeader(messageBuilder, fieldName, value)); } diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java index ebef606..dec75d8 100644 --- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java +++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java @@ -24,19 +24,14 @@ import java.time.Instant; import java.util.Collection; import java.util.Date; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; import java.util.Optional; import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; import javax.inject.Inject; import javax.mail.internet.SharedInputStream; import org.apache.james.jmap.draft.model.Attachment; import org.apache.james.jmap.draft.model.BlobId; -import org.apache.james.jmap.draft.model.Emailer; import org.apache.james.jmap.draft.model.Keywords; import org.apache.james.jmap.draft.model.MessagePreviewGenerator; import org.apache.james.jmap.draft.utils.HtmlTextExtractor; @@ -48,31 +43,21 @@ import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MessageAttachment; import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MessageResult; -import org.apache.james.mime4j.dom.address.AddressList; -import org.apache.james.mime4j.dom.address.Mailbox; -import org.apache.james.mime4j.dom.address.MailboxList; -import org.apache.james.mime4j.stream.Field; +import org.apache.james.mime4j.dom.Message; import org.apache.james.mime4j.stream.MimeConfig; -import org.apache.james.mime4j.util.MimeUtil; import org.apache.james.util.mime.MessageContentExtractor; import org.apache.james.util.mime.MessageContentExtractor.MessageContent; import com.github.steveash.guavate.Guavate; import com.google.common.base.Preconditions; import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Multimaps; import com.google.common.collect.Sets; public class MessageFullViewFactory implements MessageViewFactory<MessageFullView> { - public static final String JMAP_MULTIVALUED_FIELD_DELIMITER = "\n"; - private final BlobManager blobManager; private final MessagePreviewGenerator messagePreview; private final MessageContentExtractor messageContentExtractor; private final HtmlTextExtractor htmlTextExtractor; - private final Keywords.KeywordsFactory keywordsFactory; @Inject public MessageFullViewFactory(BlobManager blobManager, MessagePreviewGenerator messagePreview, MessageContentExtractor messageContentExtractor, @@ -81,7 +66,6 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie this.messagePreview = messagePreview; this.messageContentExtractor = messageContentExtractor; this.htmlTextExtractor = htmlTextExtractor; - this.keywordsFactory = Keywords.lenientFactory(); } @Override @@ -90,7 +74,7 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie } public MessageFullView fromMetaDataWithContent(MetaDataWithContent message) throws MailboxException { - org.apache.james.mime4j.dom.Message mimeMessage = parse(message); + Message mimeMessage = parse(message); MessageContent messageContent = extractContent(mimeMessage); Optional<String> htmlBody = messageContent.getHtmlBody(); Optional<String> mainTextContent = mainTextContent(messageContent); @@ -133,7 +117,7 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie .build(); } - private Instant getDateFromHeaderOrInternalDateOtherwise(org.apache.james.mime4j.dom.Message mimeMessage, MetaDataWithContent message) { + private Instant getDateFromHeaderOrInternalDateOtherwise(Message mimeMessage, MetaDataWithContent message) { return Optional.ofNullable(mimeMessage.getDate()) .map(Date::toInstant) .orElse(message.getInternalDate()); @@ -153,9 +137,9 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie .orElse(messageContent.getTextBody()); } - private org.apache.james.mime4j.dom.Message parse(MetaDataWithContent message) throws MailboxException { + private Message parse(MetaDataWithContent message) throws MailboxException { try { - return org.apache.james.mime4j.dom.Message.Builder + return Message.Builder .of() .use(MimeConfig.PERMISSIVE) .parse(message.getContent()) @@ -165,71 +149,13 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie } } - private MessageContent extractContent(org.apache.james.mime4j.dom.Message mimeMessage) throws MailboxException { + private MessageContent extractContent(Message mimeMessage) throws MailboxException { try { return messageContentExtractor.extract(mimeMessage); } catch (IOException e) { throw new MailboxException("Unable to extract content: " + e.getMessage(), e); } } - - private Emailer firstFromMailboxList(MailboxList list) { - if (list == null) { - return null; - } - return list.stream() - .map(this::fromMailbox) - .findFirst() - .orElse(null); - } - - private ImmutableList<Emailer> fromAddressList(AddressList list) { - if (list == null) { - return ImmutableList.of(); - } - return list.flatten() - .stream() - .map(this::fromMailbox) - .collect(Guavate.toImmutableList()); - } - - private Emailer fromMailbox(Mailbox mailbox) { - return Emailer.builder() - .name(getNameOrAddress(mailbox)) - .email(mailbox.getAddress()) - .allowInvalid() - .build(); - } - - private String getNameOrAddress(Mailbox mailbox) { - if (mailbox.getName() != null) { - return mailbox.getName(); - } - return mailbox.getAddress(); - } - - private ImmutableMap<String, String> toMap(List<Field> fields) { - Function<Entry<String, Collection<Field>>, String> bodyConcatenator = fieldListEntry -> fieldListEntry.getValue() - .stream() - .map(Field::getBody) - .map(MimeUtil::unscrambleHeaderValue) - .collect(Collectors.toList()) - .stream() - .collect(Collectors.joining(JMAP_MULTIVALUED_FIELD_DELIMITER)); - return Multimaps.index(fields, Field::getName) - .asMap() - .entrySet() - .stream() - .collect(Guavate.toImmutableMap(Map.Entry::getKey, bodyConcatenator)); - } - - private String getHeader(org.apache.james.mime4j.dom.Message message, String header) { - Field field = message.getHeader().getField(header); - if (field == null) { - return null; - } - return field.getBody(); - } private List<Attachment> getAttachments(List<MessageAttachment> attachments) { return attachments.stream() diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java index abb3a31..9ad4610 100644 --- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java +++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java @@ -39,7 +39,7 @@ import com.google.common.collect.ImmutableMap; public class MessageHeaderView extends MessageMetadataView { - public static Builder messageHeaderBuilder() { + public static MessageHeaderView.Builder<? extends MessageHeaderView.Builder> messageHeaderBuilder() { return new Builder(); } diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactory.java new file mode 100644 index 0000000..6995b44 --- /dev/null +++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactory.java @@ -0,0 +1,94 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.jmap.draft.model.message.view; + +import java.io.IOException; +import java.time.Instant; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Optional; + +import javax.inject.Inject; + +import org.apache.james.jmap.draft.model.BlobId; +import org.apache.james.mailbox.BlobManager; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MessageResult; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.stream.MimeConfig; + +import com.google.common.base.Strings; + +public class MessageHeaderViewFactory implements MessageViewFactory<MessageHeaderView> { + private final BlobManager blobManager; + + @Inject + MessageHeaderViewFactory(BlobManager blobManager) { + this.blobManager = blobManager; + } + + @Override + public MessageHeaderView fromMessageResults(Collection<MessageResult> messageResults) throws MailboxException { + assertOneMessageId(messageResults); + + MessageResult firstMessageResult = messageResults.iterator().next(); + List<MailboxId> mailboxIds = getMailboxIds(messageResults); + + Message mimeMessage = parse(firstMessageResult); + + return MessageHeaderView.messageHeaderBuilder() + .id(firstMessageResult.getMessageId()) + .mailboxIds(mailboxIds) + .blobId(BlobId.of(blobManager.toBlobId(firstMessageResult.getMessageId()))) + .threadId(firstMessageResult.getMessageId().serialize()) + .keywords(getKeywords(messageResults)) + .size(firstMessageResult.getSize()) + .inReplyToMessageId(getHeader(mimeMessage, "in-reply-to")) + .subject(Strings.nullToEmpty(mimeMessage.getSubject()).trim()) + .headers(toMap(mimeMessage.getHeader().getFields())) + .from(firstFromMailboxList(mimeMessage.getFrom())) + .to(fromAddressList(mimeMessage.getTo())) + .cc(fromAddressList(mimeMessage.getCc())) + .bcc(fromAddressList(mimeMessage.getBcc())) + .replyTo(fromAddressList(mimeMessage.getReplyTo())) + .date(getDateFromHeaderOrInternalDateOtherwise(mimeMessage, firstMessageResult)) + .build(); + } + + private Message parse(MessageResult message) throws MailboxException { + try { + return Message.Builder + .of() + .use(MimeConfig.PERMISSIVE) + .parse(message.getFullContent().getInputStream()) + .build(); + } catch (IOException e) { + throw new MailboxException("Unable to parse message: " + e.getMessage(), e); + } + } + + private Instant getDateFromHeaderOrInternalDateOtherwise(Message mimeMessage, MessageResult message) { + return Optional.ofNullable(mimeMessage.getDate()) + .map(Date::toInstant) + .orElse(message.getInternalDate().toInstant()); + } +} diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java index 5339c13..4afb117 100644 --- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java +++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java @@ -21,19 +21,32 @@ package org.apache.james.jmap.draft.model.message.view; import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.apache.james.jmap.draft.model.Emailer; import org.apache.james.jmap.draft.model.Keywords; import org.apache.james.jmap.draft.utils.KeywordsCombiner; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MessageResult; +import org.apache.james.mime4j.dom.address.AddressList; +import org.apache.james.mime4j.dom.address.Mailbox; +import org.apache.james.mime4j.dom.address.MailboxList; +import org.apache.james.mime4j.stream.Field; +import org.apache.james.mime4j.util.MimeUtil; import com.github.steveash.guavate.Guavate; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Multimaps; public interface MessageViewFactory<T extends MessageView> { KeywordsCombiner KEYWORDS_COMBINER = new KeywordsCombiner(); Keywords.KeywordsFactory KEYWORDS_FACTORY = Keywords.lenientFactory(); + String JMAP_MULTIVALUED_FIELD_DELIMITER = "\n"; T fromMessageResults(Collection<MessageResult> messageResults) throws MailboxException; @@ -64,4 +77,63 @@ public interface MessageViewFactory<T extends MessageView> { .reduce(KEYWORDS_COMBINER) .get(); } + + default String getHeader(org.apache.james.mime4j.dom.Message message, String header) { + Field field = message.getHeader().getField(header); + if (field == null) { + return null; + } + return field.getBody(); + } + + default ImmutableMap<String, String> toMap(List<Field> fields) { + Function<Map.Entry<String, Collection<Field>>, String> bodyConcatenator = fieldListEntry -> fieldListEntry.getValue() + .stream() + .map(Field::getBody) + .map(MimeUtil::unscrambleHeaderValue) + .collect(Collectors.toList()) + .stream() + .collect(Collectors.joining(JMAP_MULTIVALUED_FIELD_DELIMITER)); + + return Multimaps.index(fields, Field::getName) + .asMap() + .entrySet() + .stream() + .collect(Guavate.toImmutableMap(Map.Entry::getKey, bodyConcatenator)); + } + + default Emailer firstFromMailboxList(MailboxList list) { + if (list == null) { + return null; + } + return list.stream() + .map(this::fromMailbox) + .findFirst() + .orElse(null); + } + + default Emailer fromMailbox(Mailbox mailbox) { + return Emailer.builder() + .name(getNameOrAddress(mailbox)) + .email(mailbox.getAddress()) + .allowInvalid() + .build(); + } + + default String getNameOrAddress(Mailbox mailbox) { + if (mailbox.getName() != null) { + return mailbox.getName(); + } + return mailbox.getAddress(); + } + + default ImmutableList<Emailer> fromAddressList(AddressList list) { + if (list == null) { + return ImmutableList.of(); + } + return list.flatten() + .stream() + .map(this::fromMailbox) + .collect(Guavate.toImmutableList()); + } } diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactoryTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactoryTest.java new file mode 100644 index 0000000..a60c17f --- /dev/null +++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactoryTest.java @@ -0,0 +1,141 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.jmap.draft.model.message.view; + +import java.util.List; +import java.util.Optional; + +import javax.mail.Flags; + +import org.apache.james.core.Username; +import org.apache.james.jmap.draft.model.BlobId; +import org.apache.james.jmap.draft.model.Emailer; +import org.apache.james.jmap.draft.model.Keyword; +import org.apache.james.jmap.draft.model.Keywords; +import org.apache.james.jmap.draft.model.Number; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageIdManager; +import org.apache.james.mailbox.MessageManager; +import org.apache.james.mailbox.inmemory.InMemoryMailboxManager; +import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources; +import org.apache.james.mailbox.model.ComposedMessageId; +import org.apache.james.mailbox.model.FetchGroupImpl; +import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.model.MessageRange; +import org.apache.james.mailbox.model.MessageResult; +import org.apache.james.util.ClassLoaderUtils; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +class MessageHeaderViewFactoryTest { + private static final Username BOB = Username.of("bob@local"); + + private MessageIdManager messageIdManager; + private MessageHeaderViewFactory testee; + private MailboxSession session; + private MessageManager bobInbox; + private MessageManager bobMailbox; + private ComposedMessageId message1; + + @BeforeEach + void setUp() throws Exception { + InMemoryIntegrationResources resources = InMemoryIntegrationResources.defaultResources(); + messageIdManager = resources.getMessageIdManager(); + InMemoryMailboxManager mailboxManager = resources.getMailboxManager(); + + session = mailboxManager.createSystemSession(BOB); + MailboxId bobInboxId = mailboxManager.createMailbox(MailboxPath.inbox(session), session).get(); + MailboxId bobMailboxId = mailboxManager.createMailbox(MailboxPath.forUser(BOB, "anotherMailbox"), session).get(); + + bobInbox = mailboxManager.getMailbox(bobInboxId, session); + bobMailbox = mailboxManager.getMailbox(bobMailboxId, session); + + message1 = bobInbox.appendMessage(MessageManager.AppendCommand.builder() + .withFlags(new Flags(Flags.Flag.SEEN)) + .build(ClassLoaderUtils.getSystemResourceAsSharedStream("fullMessage.eml")), + session); + + testee = new MessageHeaderViewFactory(resources.getBlobManager()); + } + + @Test + void fromMessageResultsShouldReturnCorrectView() throws Exception { + List<MessageResult> messages = messageIdManager + .getMessages(ImmutableList.of(message1.getMessageId()), FetchGroupImpl.MINIMAL, session); + + Emailer bobEmail = Emailer.builder().name(BOB.getLocalPart()).email(BOB.asString()).build(); + Emailer aliceEmail = Emailer.builder().name("alice").email("alice@local").build(); + Emailer jackEmail = Emailer.builder().name("jack").email("jack@local").build(); + Emailer jacobEmail = Emailer.builder().name("jacob").email("jacob@local").build(); + + ImmutableMap<String, String> headersMap = ImmutableMap.<String, String>builder() + .put("Content-Type", "multipart/mixed; boundary=\"------------7AF1D14DE1DFA16229726B54\"") + .put("Date", "Tue, 7 Jun 2016 16:23:37 +0200") + .put("From", "alice <alice@local>") + .put("To", "bob <bob@local>") + .put("Subject", "Full message") + .put("Mime-Version", "1.0") + .put("Message-ID", "<[email protected]>") + .put("Cc", "jack <jack@local>, jacob <jacob@local>") + .put("Bcc", "alice <alice@local>") + .put("Reply-to", "alice <alice@local>") + .put("In-reply-to", "bob@local") + .build(); + + MessageHeaderView actual = testee.fromMessageResults(messages); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(actual.getId()).isEqualTo(message1.getMessageId()); + softly.assertThat(actual.getMailboxIds()).containsExactly(bobInbox.getId()); + softly.assertThat(actual.getThreadId()).isEqualTo(message1.getMessageId().serialize()); + softly.assertThat(actual.getSize()).isEqualTo(Number.fromLong(2255)); + softly.assertThat(actual.getKeywords()).isEqualTo(Keywords.strictFactory().from(Keyword.SEEN).asMap()); + softly.assertThat(actual.getBlobId()).isEqualTo(BlobId.of(message1.getMessageId().serialize())); + softly.assertThat(actual.getInReplyToMessageId()).isEqualTo(Optional.of(BOB.asString())); + softly.assertThat(actual.getHeaders()).isEqualTo(headersMap); + softly.assertThat(actual.getFrom()).isEqualTo(Optional.of(aliceEmail)); + softly.assertThat(actual.getTo()).isEqualTo(ImmutableList.of(bobEmail)); + softly.assertThat(actual.getCc()).isEqualTo(ImmutableList.of(jackEmail, jacobEmail)); + softly.assertThat(actual.getBcc()).isEqualTo(ImmutableList.of(aliceEmail)); + softly.assertThat(actual.getReplyTo()).isEqualTo(ImmutableList.of(aliceEmail)); + softly.assertThat(actual.getSubject()).isEqualTo("Full message"); + softly.assertThat(actual.getDate()).isEqualTo("2016-06-07T14:23:37Z"); + }); + } + + @Test + void fromMessageResultsShouldCombineKeywords() throws Exception { + messageIdManager.setInMailboxes(message1.getMessageId(), ImmutableList.of(bobInbox.getId(), bobMailbox.getId()), session); + bobMailbox.setFlags(new Flags(Flags.Flag.FLAGGED), MessageManager.FlagsUpdateMode.REPLACE, MessageRange.all(), session); + + List<MessageResult> messages = messageIdManager + .getMessages(ImmutableList.of(message1.getMessageId()), FetchGroupImpl.MINIMAL, session); + + MessageHeaderView actual = testee.fromMessageResults(messages); + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(actual.getId()).isEqualTo(message1.getMessageId()); + softly.assertThat(actual.getKeywords()).isEqualTo(Keywords.strictFactory().from(Keyword.SEEN, Keyword.FLAGGED).asMap()); + }); + } +} diff --git a/server/protocols/jmap-draft/src/test/resources/fullMessage.eml b/server/protocols/jmap-draft/src/test/resources/fullMessage.eml new file mode 100644 index 0000000..daf28d3 --- /dev/null +++ b/server/protocols/jmap-draft/src/test/resources/fullMessage.eml @@ -0,0 +1,60 @@ +Reply-to: alice <alice@local> +In-reply-to: bob@local +Mime-Version: 1.0 +To: bob <bob@local> +From: alice <alice@local> +Cc: jack <jack@local>, jacob <jacob@local> +Bcc: alice <alice@local> +Subject: Full message +Message-ID: <[email protected]> +Date: Tue, 7 Jun 2016 16:23:37 +0200 +Content-Type: multipart/mixed; + boundary="------------7AF1D14DE1DFA16229726B54" + +This is a multi-part message in MIME format. +--------------7AF1D14DE1DFA16229726B54 +Content-Type: multipart/alternative; + boundary="------------172F9470CFA3BF3417835D92" + + +--------------172F9470CFA3BF3417835D92 +Content-Type: text/plain; charset=utf-8; format=flowed +Content-Transfer-Encoding: 7bit + +/blabla/ +*bloblo* + +--------------172F9470CFA3BF3417835D92 +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: 7bit + +<i>blabla</i> +<b>bloblo</b> + +--------------172F9470CFA3BF3417835D92-- + +--------------7AF1D14DE1DFA16229726B54 +Content-Type: image/jpeg; + name="4037_014.jpg" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="4037_014.jpg" + +/9j/4X2cRXhpZgAASUkqAAgAAAANAA8BAgAKAAAAqgAAABABAgAJAAAAtAAAABIBAwABAAAA +AQAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAADEBAgAKAAAAzgAAADIB +AgAUAAAA2AAAABMCAwABAAAAAgAAAGmHBAABAAAAfAIAAKXEBwDQAAAA7AAAANLGBwBAAAAA +vAEAANPGBwCAAAAA/AEAAEwqAABQYW5hc29uaWMARE1DLUZaNDUAALQAAAABAAAAtAAAAAEA +AABWZXIuMS4wICAAMjAxNDowMjoyNSAxMDozMjowOQBQcmludElNADAyNTAAAA4AAQAWABYA +AgAAAAAAAwBkAAAABwAAAAAACAAAAAAACQAAAAAACgAAAAAACwCsAAAADAAAAAAADQAAAAAA +DgDEAAAAAAEFAAAAAQEBAAAAEAGAAAAACREAABAnAAALDwAAECcAAJcFAAAQJwAAsAgAABAn +AAABHAAAECcAAF4CAAAQJwAAiwAAABAnAADLAwAAECcAAOUbAAAQJwAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + +--------------7AF1D14DE1DFA16229726B54-- --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
