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 31fe9b08e2ec0c447149667ccdac2d442cd2c0cb Author: Benoit Tellier <[email protected]> AuthorDate: Thu Nov 21 15:35:59 2019 +0700 JAMES-2988 Deduce read levels from MessageProperties --- .../jmap/draft/methods/GetMessagesMethod.java | 1 + .../james/jmap/draft/model/MessageProperties.java | 109 +++++++++++++++------ .../jmap/draft/model/MessagePropertiesTest.java | 96 ++++++++++++++++++ 3 files changed, 174 insertions(+), 32 deletions(-) diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessagesMethod.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessagesMethod.java index faae6f4..1b414a0 100644 --- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessagesMethod.java +++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessagesMethod.java @@ -130,6 +130,7 @@ public class GetMessagesMethod implements Method { getMessagesRequest.getAccountId().ifPresent((input) -> notImplemented("accountId")); try { + MessageProperties.ReadLevel readLevel = getMessagesRequest.getProperties().computeReadLevel(); return GetMessagesResponse.builder() .messages( messageIdManager.getMessages(getMessagesRequest.getIds(), FetchGroupImpl.FULL_CONTENT, mailboxSession) diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/MessageProperties.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/MessageProperties.java index 2bebd95..13d8f9c 100644 --- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/MessageProperties.java +++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/MessageProperties.java @@ -71,6 +71,28 @@ public class MessageProperties { .ensureHeadersMessageProperty(); } + public ReadLevel computeReadLevel() { + Stream<ReadLevel> readLevels = Stream.concat(this.buildOutputMessageProperties() + .stream() + .map(MessageProperty::getReadLevel), + headerPropertiesReadLevel()); + + // If `null`, all properties will be fetched (JMAP Draft) + // This defer from RFC-8621 behavior (not implemented here) + // If omitted, this defaults to: [ "partId", "blobId", "size", "name", "type", "charset", "disposition", "cid", + // "language", "location" ] + return readLevels.reduce(ReadLevel::combine) + .orElse(ReadLevel.Full); + + } + + private Stream<ReadLevel> headerPropertiesReadLevel() { + return headersProperties.map(collection -> + collection.stream() + .map(any -> ReadLevel.Header)) + .orElse(Stream.of()); + } + private ImmutableSet<MessageProperty> buildOutputMessageProperties() { return this.messageProperties.orElseGet(MessageProperty::allOutputProperties); } @@ -112,57 +134,62 @@ public class MessageProperties { return this; } - private enum PropertyType { INPUTONLY, INPUTOUTPUT } public enum MessageProperty implements Property { - id("id"), - blobId("blobId"), - threadId("threadId"), - mailboxIds("mailboxIds"), - inReplyToMessageId("inReplyToMessageId"), - isUnread("isUnread"), - isFlagged("isFlagged"), - isAnswered("isAnswered"), - isDraft("isDraft"), - isForwarded("isForwarded"), - hasAttachment("hasAttachment"), - headers("headers"), - from("from"), - to("to"), - cc("cc"), - bcc("bcc"), - replyTo("replyTo"), - subject("subject"), - date("date"), - size("size"), - preview("preview"), - textBody("textBody"), - htmlBody("htmlBody"), - attachments("attachments"), - attachedMessages("attachedMessages"), - keywords("keywords"), - body("body", PropertyType.INPUTONLY); + id("id", ReadLevel.Metadata), + blobId("blobId", ReadLevel.Metadata), + threadId("threadId", ReadLevel.Metadata), + mailboxIds("mailboxIds", ReadLevel.Metadata), + inReplyToMessageId("inReplyToMessageId", ReadLevel.Header), + isUnread("isUnread", ReadLevel.Metadata), + isFlagged("isFlagged", ReadLevel.Metadata), + isAnswered("isAnswered", ReadLevel.Metadata), + isDraft("isDraft", ReadLevel.Metadata), + isForwarded("isForwarded", ReadLevel.Metadata), + hasAttachment("hasAttachment", ReadLevel.Full), + headers("headers", ReadLevel.Header), + from("from", ReadLevel.Header), + to("to", ReadLevel.Header), + cc("cc", ReadLevel.Header), + bcc("bcc", ReadLevel.Header), + replyTo("replyTo", ReadLevel.Header), + subject("subject", ReadLevel.Header), + date("date", ReadLevel.Header), + size("size", ReadLevel.Metadata), + preview("preview", ReadLevel.Full), + textBody("textBody", ReadLevel.Full), + htmlBody("htmlBody", ReadLevel.Full), + attachments("attachments", ReadLevel.Full), + attachedMessages("attachedMessages", ReadLevel.Full), + keywords("keywords", ReadLevel.Metadata), + body("body", PropertyType.INPUTONLY, ReadLevel.Full); private final String property; private final PropertyType type; + private final ReadLevel readLevel; - MessageProperty(String property) { - this(property, PropertyType.INPUTOUTPUT); + MessageProperty(String property, ReadLevel readLevel) { + this(property, PropertyType.INPUTOUTPUT, readLevel); } - MessageProperty(String property, PropertyType type) { + MessageProperty(String property, PropertyType type, ReadLevel readLevel) { this.property = property; this.type = type; + this.readLevel = readLevel; } @Override public String asFieldName() { return property; } + + public ReadLevel getReadLevel() { + return readLevel; + } public static Stream<MessageProperty> find(String property) { Preconditions.checkNotNull(property); @@ -184,7 +211,25 @@ public class MessageProperties { } } } - + + public enum ReadLevel { + Metadata(0), + Header(1), + Full(2); + + static ReadLevel combine(ReadLevel readLevel1, ReadLevel readLevel2) { + if (readLevel1.priority > readLevel2.priority) { + return readLevel1; + } + return readLevel2; + } + + private final int priority; + + ReadLevel(int priority) { + this.priority = priority; + } + } public static class HeaderProperty implements Property { diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/MessagePropertiesTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/MessagePropertiesTest.java index 78bb1e7..82738b7 100644 --- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/MessagePropertiesTest.java +++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/MessagePropertiesTest.java @@ -25,6 +25,7 @@ import java.util.Optional; import org.apache.james.jmap.draft.model.MessageProperties.HeaderProperty; import org.apache.james.jmap.draft.model.MessageProperties.MessageProperty; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import com.google.common.collect.ImmutableSet; @@ -87,4 +88,99 @@ class MessagePropertiesTest { value -> assertThat(value).contains(HeaderProperty.fromFieldName("x-spam-score")) ); } + + @Test + void computeReadLevelShouldReturnHeaderWhenOnlyHeaderProperties() { + MessageProperties actual = new MessageProperties( + Optional.of(ImmutableSet.of("headers.X-Spam-Score"))).toOutputProperties(); + + assertThat(actual.computeReadLevel()) + .isEqualTo(MessageProperties.ReadLevel.Header); + } + + @Test + void computeReadLevelShouldReturnMetadataWhenOnlyKeywordProperty() { + MessageProperties actual = new MessageProperties( + Optional.of(ImmutableSet.of("keywords"))).toOutputProperties(); + + assertThat(actual.computeReadLevel()) + .isEqualTo(MessageProperties.ReadLevel.Metadata); + } + + @Test + void computeReadLevelShouldReturnFullWhenHtmlBodyProperty() { + MessageProperties actual = new MessageProperties( + Optional.of(ImmutableSet.of("htmlBody"))).toOutputProperties(); + + assertThat(actual.computeReadLevel()) + .isEqualTo(MessageProperties.ReadLevel.Full); + } + + @Test + void computeReadLevelShouldCombineReadLevels() { + MessageProperties actual = new MessageProperties( + Optional.of(ImmutableSet.of("headers.X-Spam-Score", "keywords"))).toOutputProperties(); + + assertThat(actual.computeReadLevel()) + .isEqualTo(MessageProperties.ReadLevel.Header); + } + + @Nested + class ReadLevelTest { + @Test + void combineShouldReturnMetadataWhenOnlyMetadata() { + assertThat(MessageProperties.ReadLevel.combine( + MessageProperties.ReadLevel.Metadata, + MessageProperties.ReadLevel.Metadata)) + .isEqualTo(MessageProperties.ReadLevel.Metadata); + } + + @Test + void combineShouldReturnHeaderWhenOnlyHeader() { + assertThat(MessageProperties.ReadLevel.combine( + MessageProperties.ReadLevel.Header, + MessageProperties.ReadLevel.Header)) + .isEqualTo(MessageProperties.ReadLevel.Header); + } + + @Test + void combineShouldReturnFullWhenOnlyFull() { + assertThat(MessageProperties.ReadLevel.combine( + MessageProperties.ReadLevel.Full, + MessageProperties.ReadLevel.Full)) + .isEqualTo(MessageProperties.ReadLevel.Full); + } + + @Test + void combineShouldReturnHeaderWhenHeaderAndMetadata() { + assertThat(MessageProperties.ReadLevel.combine( + MessageProperties.ReadLevel.Metadata, + MessageProperties.ReadLevel.Header)) + .isEqualTo(MessageProperties.ReadLevel.Header); + } + + @Test + void combineShouldReturnFullWhenFullAndMetadata() { + assertThat(MessageProperties.ReadLevel.combine( + MessageProperties.ReadLevel.Metadata, + MessageProperties.ReadLevel.Full)) + .isEqualTo(MessageProperties.ReadLevel.Full); + } + + @Test + void combineShouldReturnFullWhenFullAndHeader() { + assertThat(MessageProperties.ReadLevel.combine( + MessageProperties.ReadLevel.Header, + MessageProperties.ReadLevel.Full)) + .isEqualTo(MessageProperties.ReadLevel.Full); + } + + @Test + void combineShouldCommute() { + assertThat(MessageProperties.ReadLevel.combine( + MessageProperties.ReadLevel.Full, + MessageProperties.ReadLevel.Header)) + .isEqualTo(MessageProperties.ReadLevel.Full); + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
