JAMES-1785 Implement move feature on JMAP using setInMailboxes
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/89994c30 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/89994c30 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/89994c30 Branch: refs/heads/master Commit: 89994c30809c7a963938a7a6eebe9b62baa62774 Parents: 54fe9a4 Author: Quynh Nguyen <[email protected]> Authored: Wed Jan 18 11:29:33 2017 +0700 Committer: Quynh Nguyen <[email protected]> Committed: Tue Jan 24 09:46:05 2017 +0700 ---------------------------------------------------------------------- .../methods/SetMessagesUpdateProcessor.java | 49 ++++++++++++++++++-- .../james/jmap/model/UpdateMessagePatch.java | 32 +++++++------ .../methods/SetMessagesUpdateProcessorTest.java | 4 +- 3 files changed, 64 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/89994c30/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java index ba55a8d..f04e180 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessor.java @@ -28,21 +28,28 @@ import java.util.stream.Stream; import javax.inject.Inject; import javax.mail.Flags; +import org.apache.commons.lang.NotImplementedException; import org.apache.james.jmap.model.MessageProperties; import org.apache.james.jmap.model.SetError; import org.apache.james.jmap.model.SetMessagesRequest; import org.apache.james.jmap.model.SetMessagesResponse; import org.apache.james.jmap.model.UpdateMessagePatch; +import org.apache.james.jmap.model.mailbox.Role; +import org.apache.james.jmap.utils.SystemMailboxesProvider; +import org.apache.james.mailbox.MailboxManager; import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MessageIdManager; import org.apache.james.mailbox.MessageManager; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.FetchGroupImpl; +import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MailboxId.Factory; import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MessageResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.github.steveash.guavate.Guavate; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -54,13 +61,21 @@ public class SetMessagesUpdateProcessor implements SetMessagesProcessor { private final UpdateMessagePatchConverter updatePatchConverter; private final MessageIdManager messageIdManager; + private final Factory mailboxIdFactory; + private final MailboxManager mailboxManager; + private final SystemMailboxesProvider systemMailboxesProvider; @Inject @VisibleForTesting SetMessagesUpdateProcessor( - UpdateMessagePatchConverter updatePatchConverter, - MessageIdManager messageIdManager) { + UpdateMessagePatchConverter updatePatchConverter, + MessageIdManager messageIdManager, + Factory mailboxIdFactory, + MailboxManager mailboxManager, SystemMailboxesProvider systemMailboxesProvider) { this.updatePatchConverter = updatePatchConverter; this.messageIdManager = messageIdManager; + this.mailboxIdFactory = mailboxIdFactory; + this.mailboxManager = mailboxManager; + this.systemMailboxesProvider = systemMailboxesProvider; } public SetMessagesResponse process(SetMessagesRequest request, MailboxSession mailboxSession) { @@ -78,14 +93,16 @@ public class SetMessagesUpdateProcessor implements SetMessagesProcessor { SetMessagesResponse.Builder builder) { try { List<MessageResult> messages = messageIdManager.getMessages(ImmutableList.of(messageId), FetchGroupImpl.MINIMAL, mailboxSession); + if (messages.isEmpty()) { addMessageIdNotFoundToResponse(messageId, builder); } else { + setInMailboxes(messageId, updateMessagePatch, mailboxSession); Optional<MailboxException> updateError = messages.stream() .flatMap(message -> updateFlags(messageId, updateMessagePatch, mailboxSession, message)) .findAny(); if (updateError.isPresent()) { - updateError.ifPresent(e -> handleMessageUpdateException(messageId, builder, e)); + handleMessageUpdateException(messageId, builder, updateError.get()); } else { builder.updated(ImmutableList.of(messageId)); } @@ -106,6 +123,28 @@ public class SetMessagesUpdateProcessor implements SetMessagesProcessor { } } + private void setInMailboxes(MessageId messageId, UpdateMessagePatch updateMessagePatch, MailboxSession mailboxSession) throws MailboxException { + Optional<List<String>> serializedMailboxIds = updateMessagePatch.getMailboxIds(); + if (serializedMailboxIds.isPresent()) { + List<MailboxId> mailboxIds = serializedMailboxIds.get() + .stream() + .map(mailboxId -> mailboxIdFactory.fromString(mailboxId)) + .collect(Guavate.toImmutableList()); + + if (isMoveToTrash(mailboxSession, mailboxIds)) { + throw new NotImplementedException("Do not support move to trash"); + } + + messageIdManager.setInMailboxes(messageId, mailboxIds, mailboxSession); + } + } + + private boolean isMoveToTrash(MailboxSession mailboxSession, List<MailboxId> mailboxIds) throws MailboxException { + return mailboxIds.size() == 1 + && mailboxIds.get(0) + .equals(systemMailboxesProvider.findMailbox(Role.TRASH, mailboxSession).getId()); + } + private void addMessageIdNotFoundToResponse(MessageId messageId, SetMessagesResponse.Builder builder) { builder.notUpdated(ImmutableMap.of(messageId, SetError.builder() @@ -115,11 +154,11 @@ public class SetMessagesUpdateProcessor implements SetMessagesProcessor { .build())); } - private void handleMessageUpdateException(MessageId messageId, + private SetMessagesResponse.Builder handleMessageUpdateException(MessageId messageId, SetMessagesResponse.Builder builder, MailboxException e) { LOGGER.error("An error occurred when updating a message", e); - builder.notUpdated(ImmutableMap.of(messageId, SetError.builder() + return builder.notUpdated(ImmutableMap.of(messageId, SetError.builder() .type("anErrorOccurred") .description("An error occurred when updating a message") .build())); http://git-wip-us.apache.org/repos/asf/james-project/blob/89994c30/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java index 9ffac27..cc0e184 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/UpdateMessagePatch.java @@ -25,14 +25,14 @@ import java.util.Set; import javax.mail.Flags; -import com.google.common.collect.ImmutableSet; - -import org.apache.commons.lang.NotImplementedException; import org.apache.james.jmap.methods.ValidationResult; + import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; @JsonDeserialize(builder = UpdateMessagePatch.Builder.class) public class UpdateMessagePatch { @@ -43,16 +43,14 @@ public class UpdateMessagePatch { @JsonPOJOBuilder(withPrefix = "") public static class Builder { - private ImmutableList.Builder<String> mailboxIds = ImmutableList.builder(); + private Optional<List<String>> mailboxIds = Optional.empty(); private Optional<Boolean> isFlagged = Optional.empty(); private Optional<Boolean> isUnread = Optional.empty(); private Optional<Boolean> isAnswered = Optional.empty(); - private Set<ValidationResult> validationResult = ImmutableSet.of(); + private Set<ValidationResult> validationResult = Sets.newHashSet(); - public Builder mailboxIds(Optional<List<String>> mailboxIds) { - if (mailboxIds.isPresent()) { - throw new NotImplementedException("moving a message is not supported"); - } + public Builder mailboxIds(List<String> mailboxIds) { + this.mailboxIds = Optional.of(ImmutableList.copyOf(mailboxIds)); return this; } @@ -72,16 +70,22 @@ public class UpdateMessagePatch { } public Builder validationResult(Set<ValidationResult> validationResult) { - this.validationResult = ImmutableSet.copyOf(validationResult); + this.validationResult.addAll(validationResult); return this; } public UpdateMessagePatch build() { - return new UpdateMessagePatch(mailboxIds.build(), isUnread, isFlagged, isAnswered, ImmutableList.copyOf(validationResult)); + if (mailboxIds.isPresent() && mailboxIds.get().isEmpty()) { + validationResult(ImmutableSet.of(ValidationResult.builder() + .property("mailboxIds") + .message("mailboxIds property is not supposed to be empty") + .build())); + } + return new UpdateMessagePatch(mailboxIds, isUnread, isFlagged, isAnswered, ImmutableList.copyOf(validationResult)); } } - private final List<String> mailboxIds; + private final Optional<List<String>> mailboxIds; private final Optional<Boolean> isUnread; private final Optional<Boolean> isFlagged; private final Optional<Boolean> isAnswered; @@ -89,7 +93,7 @@ public class UpdateMessagePatch { private final ImmutableList<ValidationResult> validationErrors; @VisibleForTesting - UpdateMessagePatch(List<String> mailboxIds, + UpdateMessagePatch(Optional<List<String>> mailboxIds, Optional<Boolean> isUnread, Optional<Boolean> isFlagged, Optional<Boolean> isAnswered, @@ -102,7 +106,7 @@ public class UpdateMessagePatch { this.validationErrors = validationResults; } - public List<String> getMailboxIds() { + public Optional<List<String>> getMailboxIds() { return mailboxIds; } http://git-wip-us.apache.org/repos/asf/james-project/blob/89994c30/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessorTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessorTest.java index d6478ff..5b0387a 100644 --- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessorTest.java +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesUpdateProcessorTest.java @@ -42,7 +42,7 @@ public class SetMessagesUpdateProcessorTest { @Test public void processShouldReturnEmptyUpdatedWhenRequestHasEmptyUpdate() { - SetMessagesUpdateProcessor sut = new SetMessagesUpdateProcessor(null, null); + SetMessagesUpdateProcessor sut = new SetMessagesUpdateProcessor(null, null, null, null, null); SetMessagesRequest requestWithEmptyUpdate = SetMessagesRequest.builder().build(); SetMessagesResponse result = sut.process(requestWithEmptyUpdate, null); @@ -66,7 +66,7 @@ public class SetMessagesUpdateProcessorTest { when(mockConverter.fromJsonNode(any(ObjectNode.class))) .thenReturn(mockInvalidPatch); - SetMessagesUpdateProcessor sut = new SetMessagesUpdateProcessor(mockConverter, null); + SetMessagesUpdateProcessor sut = new SetMessagesUpdateProcessor(mockConverter, null, null, null, null); MessageId requestMessageId = TestMessageId.of(1); SetMessagesRequest requestWithInvalidUpdate = SetMessagesRequest.builder() .update(ImmutableMap.of(requestMessageId, JsonNodeFactory.instance.objectNode())) --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
