JAMES-2110 SetMessage with creation should support keywords for flags
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/78a4a57d Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/78a4a57d Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/78a4a57d Branch: refs/heads/master Commit: 78a4a57de45038e63011e867e9a46419540cb4e5 Parents: c1387ef Author: quynhn <[email protected]> Authored: Tue Aug 15 16:42:17 2017 +0700 Committer: Raphael Ouazana <[email protected]> Committed: Thu Aug 24 15:47:27 2017 +0200 ---------------------------------------------------------------------- .../methods/SetMessagesCreationProcessor.java | 30 +++----- .../james/jmap/model/CreationMessage.java | 73 ++++++++++---------- .../SetMessagesCreationProcessorTest.java | 57 ++++++++++++++- 3 files changed, 101 insertions(+), 59 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/78a4a57d/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java index 34bd029..bb9f189 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java @@ -20,14 +20,12 @@ package org.apache.james.jmap.methods; import static org.apache.james.jmap.methods.Method.JMAP_PREFIX; - import java.io.IOException; import java.util.Date; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - import javax.inject.Inject; import javax.mail.Flags; import javax.mail.MessagingException; @@ -40,6 +38,7 @@ import org.apache.james.jmap.model.Attachment; import org.apache.james.jmap.model.BlobId; import org.apache.james.jmap.model.CreationMessage; import org.apache.james.jmap.model.CreationMessageId; +import org.apache.james.jmap.model.Keywords; import org.apache.james.jmap.model.Message; import org.apache.james.jmap.model.MessageFactory; import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent; @@ -70,6 +69,7 @@ import org.apache.james.metrics.api.MetricFactory; import org.apache.james.metrics.api.TimeMetric; import org.apache.james.util.OptionalConverter; import org.apache.mailet.Mail; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,6 +82,7 @@ import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; + public class SetMessagesCreationProcessor implements SetMessagesProcessor { private static final Logger LOG = LoggerFactory.getLogger(SetMailboxesCreationProcessor.class); @@ -290,16 +291,20 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor { byte[] messageContent = mimeMessageConverter.convert(createdEntry, messageAttachments); SharedByteArrayInputStream content = new SharedByteArrayInputStream(messageContent); Date internalDate = Date.from(createdEntry.getValue().getDate().toInstant()); - Flags flags = getMessageFlags(createdEntry.getValue()); + + Flags flags = createdEntry.getValue() + .getKeywords() + .map(Keywords::asFlags) + .orElse(new Flags()); ComposedMessageId message = outbox.appendMessage(content, internalDate, session, flags.contains(Flags.Flag.RECENT), flags); return MetaDataWithContent.builder() .uid(message.getUid()) .flags(flags) - .size(messageContent.length) .internalDate(internalDate.toInstant()) .sharedContent(content) + .size(messageContent.length) .attachments(messageAttachments) .mailboxId(outbox.getId()) .messageId(message.getMessageId()) @@ -332,23 +337,6 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor { } } - private Flags getMessageFlags(CreationMessage message) { - Flags result = new Flags(); - if (!message.isIsUnread()) { - result.add(Flags.Flag.SEEN); - } - if (message.isIsFlagged()) { - result.add(Flags.Flag.FLAGGED); - } - if (message.isIsAnswered() || message.getInReplyToMessageId().isPresent()) { - result.add(Flags.Flag.ANSWERED); - } - if (message.isIsDraft()) { - result.add(Flags.Flag.DRAFT); - } - return result; - } - private MessageWithId sendMessage(CreationMessageId creationId, MetaDataWithContent message, MailboxSession session) throws MailboxException, MessagingException { Message jmapMessage = messageFactory.fromMetaDataWithContent(message); sendMessage(message, jmapMessage, session); http://git-wip-us.apache.org/repos/asf/james-project/blob/78a4a57d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java index 791b383..f67185d 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java @@ -27,7 +27,6 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; - import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; @@ -59,10 +58,10 @@ public class CreationMessage { public static class Builder { private ImmutableList<String> mailboxIds; private String inReplyToMessageId; - private boolean isUnread; - private boolean isFlagged; - private boolean isAnswered; - private boolean isDraft; + private Optional<Boolean> isUnread = Optional.empty(); + private Optional<Boolean> isFlagged = Optional.empty(); + private Optional<Boolean> isAnswered = Optional.empty(); + private Optional<Boolean> isDraft = Optional.empty(); private final ImmutableMap.Builder<String, String> headers; private Optional<DraftEmailer> from = Optional.empty(); private final ImmutableList.Builder<DraftEmailer> to; @@ -75,6 +74,7 @@ public class CreationMessage { private String htmlBody; private final ImmutableList.Builder<Attachment> attachments; private final ImmutableMap.Builder<BlobId, SubMessage> attachedMessages; + private Optional<Map<String, Boolean>> keywords = Optional.empty(); private Builder() { to = ImmutableList.builder(); @@ -101,22 +101,22 @@ public class CreationMessage { return this; } - public Builder isUnread(boolean isUnread) { + public Builder isUnread(Optional<Boolean> isUnread) { this.isUnread = isUnread; return this; } - public Builder isFlagged(boolean isFlagged) { + public Builder isFlagged(Optional<Boolean> isFlagged) { this.isFlagged = isFlagged; return this; } - public Builder isAnswered(boolean isAnswered) { + public Builder isAnswered(Optional<Boolean> isAnswered) { this.isAnswered = isAnswered; return this; } - public Builder isDraft(boolean isDraft) { + public Builder isDraft(Optional<Boolean> isDraft) { this.isDraft = isDraft; return this; } @@ -186,6 +186,11 @@ public class CreationMessage { return this; } + public Builder keywords(Map<String, Boolean> keywords) { + this.keywords = Optional.of(ImmutableMap.copyOf(keywords)); + return this; + } + private static boolean areAttachedMessagesKeysInAttachments(ImmutableList<Attachment> attachments, ImmutableMap<BlobId, SubMessage> attachedMessages) { return attachedMessages.isEmpty() || attachedMessages.keySet().stream() .anyMatch(inAttachments(attachments)); @@ -206,21 +211,29 @@ public class CreationMessage { ImmutableMap<BlobId, SubMessage> attachedMessages = this.attachedMessages.build(); Preconditions.checkState(areAttachedMessagesKeysInAttachments(attachments, attachedMessages), "'attachedMessages' keys must be in 'attachments'"); + Optional<Keywords> creationKeywords = Keywords.factory() + .throwOnImapNonExposedKeywords() + .fromMapOrOldKeyword(keywords, getOldKeywords()); + if (date == null) { date = ZonedDateTime.now(); } - return new CreationMessage(mailboxIds, Optional.ofNullable(inReplyToMessageId), isUnread, isFlagged, isAnswered, isDraft, headers.build(), from, - to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, Optional.ofNullable(textBody), Optional.ofNullable(htmlBody), attachments, attachedMessages); + return new CreationMessage(mailboxIds, Optional.ofNullable(inReplyToMessageId), headers.build(), from, + to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, Optional.ofNullable(textBody), Optional.ofNullable(htmlBody), + attachments, attachedMessages, creationKeywords); + } + + private Optional<OldKeyword> getOldKeywords() { + if (isAnswered.isPresent() || isFlagged.isPresent() || isUnread.isPresent() || isDraft.isPresent()) { + return Optional.of(new OldKeyword(isUnread, isFlagged, isAnswered, isDraft)); + } + return Optional.empty(); } } private final ImmutableList<String> mailboxIds; private final Optional<String> inReplyToMessageId; - private final boolean isUnread; - private final boolean isFlagged; - private final boolean isAnswered; - private final boolean isDraft; private final ImmutableMap<String, String> headers; private final Optional<DraftEmailer> from; private final ImmutableList<DraftEmailer> to; @@ -233,17 +246,14 @@ public class CreationMessage { private final Optional<String> htmlBody; private final ImmutableList<Attachment> attachments; private final ImmutableMap<BlobId, SubMessage> attachedMessages; + private final Optional<Keywords> keywords; @VisibleForTesting - CreationMessage(ImmutableList<String> mailboxIds, Optional<String> inReplyToMessageId, boolean isUnread, boolean isFlagged, boolean isAnswered, boolean isDraft, ImmutableMap<String, String> headers, Optional<DraftEmailer> from, + CreationMessage(ImmutableList<String> mailboxIds, Optional<String> inReplyToMessageId, ImmutableMap<String, String> headers, Optional<DraftEmailer> from, ImmutableList<DraftEmailer> to, ImmutableList<DraftEmailer> cc, ImmutableList<DraftEmailer> bcc, ImmutableList<DraftEmailer> replyTo, String subject, ZonedDateTime date, Optional<String> textBody, Optional<String> htmlBody, ImmutableList<Attachment> attachments, - ImmutableMap<BlobId, SubMessage> attachedMessages) { + ImmutableMap<BlobId, SubMessage> attachedMessages, Optional<Keywords> keywords) { this.mailboxIds = mailboxIds; this.inReplyToMessageId = inReplyToMessageId; - this.isUnread = isUnread; - this.isFlagged = isFlagged; - this.isAnswered = isAnswered; - this.isDraft = isDraft; this.headers = headers; this.from = from; this.to = to; @@ -256,6 +266,7 @@ public class CreationMessage { this.htmlBody = htmlBody; this.attachments = attachments; this.attachedMessages = attachedMessages; + this.keywords = keywords; } public ImmutableList<String> getMailboxIds() { @@ -266,22 +277,6 @@ public class CreationMessage { return inReplyToMessageId; } - public boolean isIsUnread() { - return isUnread; - } - - public boolean isIsFlagged() { - return isFlagged; - } - - public boolean isIsAnswered() { - return isAnswered; - } - - public boolean isIsDraft() { - return isDraft; - } - public ImmutableMap<String, String> getHeaders() { return headers; } @@ -334,6 +329,10 @@ public class CreationMessage { return validate().isEmpty(); } + public Optional<Keywords> getKeywords() { + return keywords; + } + public List<ValidationResult> validate() { ImmutableList.Builder<ValidationResult> errors = ImmutableList.builder(); assertValidFromProvided(errors); http://git-wip-us.apache.org/repos/asf/james-project/blob/78a4a57d/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java index cc10186..c2c36e6 100644 --- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java @@ -42,6 +42,7 @@ import org.apache.james.jmap.model.BlobId; import org.apache.james.jmap.model.CreationMessage; import org.apache.james.jmap.model.CreationMessage.DraftEmailer; import org.apache.james.jmap.model.CreationMessageId; +import org.apache.james.jmap.model.Keyword; import org.apache.james.jmap.model.MessageFactory; import org.apache.james.jmap.model.MessagePreviewGenerator; import org.apache.james.jmap.model.MessageProperties.MessageProperty; @@ -72,9 +73,12 @@ import org.apache.james.util.mime.MessageContentExtractor; import org.apache.mailet.Mail; import org.junit.Before; import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; public class SetMessagesCreationProcessorTest { @@ -115,7 +119,8 @@ public class SetMessagesCreationProcessorTest { private Optional<MessageManager> optionalOutbox; private Optional<MessageManager> optionalDrafts; - + @Rule + public ExpectedException expectedException = ExpectedException.none(); @Before public void setUp() throws MailboxException { HtmlTextExtractor htmlTextExtractor = mock(HtmlTextExtractor.class); @@ -157,6 +162,56 @@ public class SetMessagesCreationProcessorTest { } @Test + public void processShouldThrowWhenBothIsFlagAndKeywords() { + expectedException.expect(IllegalArgumentException.class); + SetMessagesRequest createMessageWithError = SetMessagesRequest.builder() + .create( + creationMessageId, + creationMessageBuilder + .mailboxId(OUTBOX_ID.serialize()) + .isAnswered(Optional.of(true)) + .keywords(ImmutableMap.of("$Answered", true)) + .build()) + .build(); + + sut.process(createMessageWithError, session); + } + + @Test + public void processShouldCreateWhenKeywords() { + SetMessagesRequest createMessageWithKeywords = SetMessagesRequest.builder() + .create( + creationMessageId, + creationMessageBuilder + .mailboxId(OUTBOX_ID.serialize()) + .keywords(ImmutableMap.of("$Answered", true)) + .build()) + .build(); + + SetMessagesResponse result = sut.process(createMessageWithKeywords, session); + + assertThat(result.getCreated()).isNotEmpty(); + assertThat(result.getNotCreated()).isEmpty(); + } + + @Test + public void processShouldCreateWhenIsFlag() { + SetMessagesRequest createMessageWithKeywords = SetMessagesRequest.builder() + .create( + creationMessageId, + creationMessageBuilder + .mailboxId(OUTBOX_ID.serialize()) + .isAnswered(Optional.of(true)) + .build()) + .build(); + + SetMessagesResponse result = sut.process(createMessageWithKeywords, session); + + assertThat(result.getCreated()).isNotEmpty(); + assertThat(result.getNotCreated()).isEmpty(); + } + + @Test public void processShouldReturnNonEmptyCreatedWhenRequestHasNonEmptyCreate() throws MailboxException { // Given sut = new SetMessagesCreationProcessor(mimeMessageConverter, mockedMailSpool, mockedMailFactory, messageFactory, fakeSystemMailboxesProvider, mockedAttachmentManager, new NoopMetricFactory()); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
