You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2017/12/14 09:04:34 UTC

[1/3] james-project git commit: JAMES-2244 Allow message creation in several mailboxes

Repository: james-project
Updated Branches:
  refs/heads/master 8e9c667e7 -> 38acce230


JAMES-2244 Allow message creation in several mailboxes

Message creation assertions concerning mailboxIds should be done explicitly on mailboxIds

Tests are then easier. The checked properties of creation entries are then easier.

Note: As drafts are still overrides to be in draft mailbox, we can not write integration test for this yet.


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/66f19b2b
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/66f19b2b
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/66f19b2b

Branch: refs/heads/master
Commit: 66f19b2b9103c2b64f1627019f6e8e5a51d98293
Parents: b812aaa
Author: benwa <bt...@linagora.com>
Authored: Tue Dec 12 16:02:04 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Dec 14 16:03:11 2017 +0700

----------------------------------------------------------------------
 .../james/jmap/methods/MessageAppender.java     | 21 ++++++-------
 .../methods/SetMessagesCreationProcessor.java   | 33 +++++++++++++-------
 .../SetMessagesCreationProcessorTest.java       | 26 +++++----------
 3 files changed, 38 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/66f19b2b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java
index 763ba27..5ca9ab3 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java
@@ -20,6 +20,7 @@
 package org.apache.james.jmap.methods;
 
 import java.util.Date;
+import java.util.List;
 import java.util.Optional;
 
 import javax.inject.Inject;
@@ -35,6 +36,7 @@ import org.apache.james.jmap.model.OldKeyword;
 import org.apache.james.mailbox.AttachmentManager;
 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.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
@@ -56,18 +58,20 @@ public class MessageAppender {
     private static final Logger LOGGER = LoggerFactory.getLogger(MessageAppender.class);
 
     private final MailboxManager mailboxManager;
+    private final MessageIdManager messageIdManager;
     private final AttachmentManager attachmentManager;
     private final MIMEMessageConverter mimeMessageConverter;
 
     @Inject
-    public MessageAppender(MailboxManager mailboxManager, AttachmentManager attachmentManager, MIMEMessageConverter mimeMessageConverter) {
+    public MessageAppender(MailboxManager mailboxManager, MessageIdManager messageIdManager, AttachmentManager attachmentManager, MIMEMessageConverter mimeMessageConverter) {
         this.mailboxManager = mailboxManager;
+        this.messageIdManager = messageIdManager;
         this.attachmentManager = attachmentManager;
         this.mimeMessageConverter = mimeMessageConverter;
     }
 
     public MessageFactory.MetaDataWithContent appendMessageInMailbox(CreationMessageEntry createdEntry,
-                                                                     MessageManager mailbox,
+                                                                     List<MailboxId> targetMailboxes,
                                                                      MailboxSession session) throws MailboxException {
         ImmutableList<MessageAttachment> messageAttachments = getMessageAttachments(session, createdEntry.getValue().getAttachments());
         byte[] messageContent = mimeMessageConverter.convert(createdEntry, messageAttachments);
@@ -75,8 +79,11 @@ public class MessageAppender {
         Date internalDate = Date.from(createdEntry.getValue().getDate().toInstant());
 
         boolean notRecent = false;
-
+        MessageManager mailbox = mailboxManager.getMailbox(targetMailboxes.get(0), session);
         ComposedMessageId message = mailbox.appendMessage(content, internalDate, session, notRecent, getFlags(createdEntry.getValue()));
+        if (targetMailboxes.size() > 0) {
+            messageIdManager.setInMailboxes(message.getMessageId(), targetMailboxes, session);
+        }
 
         return MessageFactory.MetaDataWithContent.builder()
             .uid(message.getUid())
@@ -102,14 +109,6 @@ public class MessageAppender {
                 .orElse(Keywords.DEFAULT_VALUE);
     }
 
-    public MessageFactory.MetaDataWithContent appendMessageInMailbox(CreationMessageEntry createdEntry,
-                                                                     MailboxId mailboxId,
-                                                                     MailboxSession session) throws MailboxException {
-        return appendMessageInMailbox(createdEntry,
-            mailboxManager.getMailbox(mailboxId, session),
-            session);
-    }
-
     private ImmutableList<MessageAttachment> getMessageAttachments(MailboxSession session, ImmutableList<Attachment> attachments) throws MailboxException {
         ThrowingFunction<Attachment, Optional<MessageAttachment>> toMessageAttachment = att -> messageAttachment(session, att);
         return attachments.stream()

http://git-wip-us.apache.org/repos/asf/james-project/blob/66f19b2b/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 07c087c..b8f820b 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
@@ -65,8 +65,10 @@ import org.slf4j.LoggerFactory;
 
 import com.github.fge.lambdas.Throwing;
 import com.github.fge.lambdas.functions.FunctionChainer;
+import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
 
 
 public class SetMessagesCreationProcessor implements SetMessagesProcessor {
@@ -112,8 +114,9 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private void handleCreate(CreationMessageEntry create, Builder responseBuilder, MailboxSession mailboxSession) {
         try {
-            assertAtLeastOneMailbox(create);
-            assertIsUserOwnerOfMailboxes(create, mailboxSession);
+            List<MailboxId> mailboxIds = toMailboxIds(create);
+            assertAtLeastOneMailbox(mailboxIds);
+            assertIsUserOwnerOfMailboxes(mailboxIds, mailboxSession);
             performCreate(create, responseBuilder, mailboxSession);
         } catch (MailboxSendingNotAllowedException e) {
             responseBuilder.notCreated(create.getCreationId(), 
@@ -186,7 +189,15 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
                         .build());
         }
     }
-    
+
+    private ImmutableList<MailboxId> toMailboxIds(CreationMessageEntry create) {
+        return create.getValue().getMailboxIds()
+            .stream()
+            .distinct()
+            .map(mailboxIdFactory::fromString)
+            .collect(Guavate.toImmutableList());
+    }
+
     private void performCreate(CreationMessageEntry entry, Builder responseBuilder, MailboxSession session) throws MailboxException, InvalidMailboxForCreationException, MessagingException, AttachmentsNotFoundException {
         if (isAppendToMailboxWithRole(Role.OUTBOX, entry.getValue(), session)) {
             sendMailViaOutbox(entry, responseBuilder, session);
@@ -207,8 +218,8 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         }
     }
 
-    private void assertAtLeastOneMailbox(CreationMessageEntry entry) throws MailboxException {
-        if (entry.getValue().getMailboxIds().isEmpty()) {
+    private void assertAtLeastOneMailbox(List<MailboxId> mailboxIds) throws MailboxException {
+        if (mailboxIds.isEmpty()) {
             throw new MessageHasNoMailboxException();
         }
     }
@@ -246,16 +257,15 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         attachmentChecker.assertAttachmentsExist(entry, session);
     }
 
-    @VisibleForTesting void assertIsUserOwnerOfMailboxes(CreationMessageEntry entry, MailboxSession session) throws MailboxNotOwnedException {
-        if (containsMailboxNotOwn(entry.getValue().getMailboxIds(), session)) {
+    @VisibleForTesting void assertIsUserOwnerOfMailboxes(List<MailboxId> mailboxIds, MailboxSession session) throws MailboxNotOwnedException {
+        if (containsMailboxNotOwn(mailboxIds, session)) {
             throw new MailboxNotOwnedException();
         }
     }
 
-    private boolean containsMailboxNotOwn(List<String> mailboxIds, MailboxSession session) {
+    private boolean containsMailboxNotOwn(List<MailboxId> mailboxIds, MailboxSession session) {
         FunctionChainer<MailboxId, MessageManager> findMailbox = Throwing.function(mailboxId -> mailboxManager.getMailbox(mailboxId, session));
         return mailboxIds.stream()
-            .map(mailboxIdFactory::fromString)
             .map(findMailbox.sneakyThrow())
             .map(Throwing.function(MessageManager::getMailboxPath))
             .anyMatch(path -> !path.belongsTo(session));
@@ -263,8 +273,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private MessageWithId handleOutboxMessages(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MessagingException {
         assertUserIsSender(session, entry.getValue().getFrom());
-        MessageManager outbox = getMailboxWithRole(session, Role.OUTBOX).orElseThrow(() -> new MailboxNotFoundException(Role.OUTBOX.serialize()));
-        MetaDataWithContent newMessage = messageAppender.appendMessageInMailbox(entry, outbox, session);
+        MetaDataWithContent newMessage = messageAppender.appendMessageInMailbox(entry, toMailboxIds(entry), session);
         Message jmapMessage = messageFactory.fromMetaDataWithContent(newMessage);
         Envelope envelope = Envelope.fromMessage(jmapMessage);
         messageSender.sendMessage(newMessage, envelope, session);
@@ -282,7 +291,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private MessageWithId handleDraftMessages(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MessagingException {
         MessageManager draftMailbox = getMailboxWithRole(session, Role.DRAFTS).orElseThrow(() -> new MailboxNotFoundException(Role.DRAFTS.serialize()));
-        MetaDataWithContent newMessage = messageAppender.appendMessageInMailbox(entry, draftMailbox, session);
+        MetaDataWithContent newMessage = messageAppender.appendMessageInMailbox(entry, ImmutableList.of(draftMailbox.getId()), session);
         Message jmapMessage = messageFactory.fromMetaDataWithContent(newMessage);
         return new ValueWithId.MessageWithId(entry.getCreationId(), jmapMessage);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/66f19b2b/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 0d8a9cb..ebdcc83 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
@@ -36,7 +36,6 @@ import java.util.stream.Stream;
 import javax.mail.Flags;
 
 import org.apache.james.jmap.exceptions.MailboxNotOwnedException;
-import org.apache.james.jmap.methods.ValueWithId.CreationMessageEntry;
 import org.apache.james.jmap.model.CreationMessage;
 import org.apache.james.jmap.model.CreationMessage.DraftEmailer;
 import org.apache.james.jmap.model.CreationMessageId;
@@ -54,6 +53,7 @@ import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.BlobManager;
 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.MessageUid;
 import org.apache.james.mailbox.exception.MailboxException;
@@ -135,11 +135,12 @@ public class SetMessagesCreationProcessorTest {
         mockedAttachmentManager = mock(AttachmentManager.class);
         mockedMailboxManager = mock(MailboxManager.class);
         mockedMailboxIdFactory = mock(Factory.class);
+        MessageIdManager mockMessageIdManager = mock(MessageIdManager.class);
         
         fakeSystemMailboxesProvider = new TestSystemMailboxesProvider(() -> optionalOutbox, () -> optionalDrafts);
         session = new MockMailboxSession(USER);
         MIMEMessageConverter mimeMessageConverter = new MIMEMessageConverter();
-        messageAppender = new MessageAppender(mockedMailboxManager, mockedAttachmentManager, mimeMessageConverter);
+        messageAppender = new MessageAppender(mockedMailboxManager, mockMessageIdManager, mockedAttachmentManager, mimeMessageConverter);
         messageSender = new MessageSender(mockedMailSpool, mockedMailFactory);
         sut = new SetMessagesCreationProcessor(messageFactory,
             fakeSystemMailboxesProvider,
@@ -319,15 +320,12 @@ public class SetMessagesCreationProcessorTest {
             .thenThrow(new MailboxNotFoundException(mailboxId));
         when(mockedMailboxIdFactory.fromString(mailboxId.serialize()))
             .thenReturn(mailboxId);
-        CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
-        CreationMessageEntry entry = new CreationMessageEntry(creationMessageId, creationMessageBuilder.mailboxId(mailboxId.serialize()).build());
 
-        assertThatThrownBy(() -> sut.assertIsUserOwnerOfMailboxes(entry, session));
+        assertThatThrownBy(() -> sut.assertIsUserOwnerOfMailboxes(ImmutableList.of(mailboxId), session));
     }
 
     @Test
     public void assertIsUserOwnerOfMailboxesShouldThrowWhenRetrievingMailboxPathFails() throws Exception {
-        CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
         InMemoryId mailboxId = InMemoryId.of(6789);
         MessageManager mailbox = mock(MessageManager.class);
         when(mockedMailboxManager.getMailbox(mailboxId, session))
@@ -337,14 +335,11 @@ public class SetMessagesCreationProcessorTest {
         when(mailbox.getMailboxPath())
             .thenThrow(new MailboxException());
 
-        CreationMessageEntry entry = new CreationMessageEntry(creationMessageId, creationMessageBuilder.mailboxId(mailboxId.serialize()).build());
-
-        assertThatThrownBy(() -> sut.assertIsUserOwnerOfMailboxes(entry, session));
+        assertThatThrownBy(() -> sut.assertIsUserOwnerOfMailboxes(ImmutableList.of(mailboxId), session));
     }
 
     @Test
     public void assertIsUserOwnerOfMailboxesShouldThrowWhenUserIsNotTheOwnerOfTheMailbox() throws Exception {
-        CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
         InMemoryId mailboxId = InMemoryId.of(6789);
         MessageManager mailbox = mock(MessageManager.class);
         when(mockedMailboxManager.getMailbox(mailboxId, session))
@@ -354,16 +349,12 @@ public class SetMessagesCreationProcessorTest {
         when(mailbox.getMailboxPath())
             .thenReturn(MailboxPath.forUser("otheruser@example.com", mailboxId.serialize()));
 
-
-        CreationMessageEntry entry = new CreationMessageEntry(creationMessageId, creationMessageBuilder.mailboxId(mailboxId.serialize()).build());
-
-        assertThatThrownBy(() -> sut.assertIsUserOwnerOfMailboxes(entry, session))
+        assertThatThrownBy(() -> sut.assertIsUserOwnerOfMailboxes(ImmutableList.of(mailboxId), session))
             .isInstanceOf(MailboxNotOwnedException.class);
     }
 
     @Test
     public void assertIsUserOwnerOfMailboxesShouldNotThrowWhenUserIsTheOwnerOfTheMailbox() throws Exception {
-        CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
         InMemoryId mailboxId = InMemoryId.of(6789);
         MessageManager mailbox = mock(MessageManager.class);
         when(mockedMailboxManager.getMailbox(mailboxId, session))
@@ -373,10 +364,7 @@ public class SetMessagesCreationProcessorTest {
         when(mailbox.getMailboxPath())
             .thenReturn(MailboxPath.forUser(USER, mailboxId.serialize()));
 
-
-        CreationMessageEntry entry = new CreationMessageEntry(creationMessageId, creationMessageBuilder.mailboxId(mailboxId.serialize()).build());
-
-        sut.assertIsUserOwnerOfMailboxes(entry, session);
+        sut.assertIsUserOwnerOfMailboxes(ImmutableList.of(mailboxId), session);
     }
     
     public static class TestSystemMailboxesProvider implements SystemMailboxesProvider {


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


[2/3] james-project git commit: JAMES-2244 A message should belong to at least one mailbox

Posted by bt...@apache.org.
JAMES-2244 A message should belong to at least one mailbox

This is an investment for mater (current code overrides Draft mailboxIds properties to draft mailboxes).
If this override is removed, we need to check the list of mailboxIds is not empty.


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/b812aaad
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/b812aaad
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/b812aaad

Branch: refs/heads/master
Commit: b812aaad4c76e90de8c12370f35f7cdc4a06ad26
Parents: 8e9c667
Author: benwa <bt...@linagora.com>
Authored: Tue Dec 12 14:53:56 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Dec 14 16:03:11 2017 +0700

----------------------------------------------------------------------
 .../integration/SetMessagesMethodTest.java      | 37 ++++++++++++++++++++
 .../MessageHasNoMailboxException.java           | 24 +++++++++++++
 .../methods/SetMessagesCreationProcessor.java   | 16 +++++++++
 3 files changed, 77 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/b812aaad/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
index 3842a0e..3a6893f 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
@@ -1356,6 +1356,43 @@ public abstract class SetMessagesMethodTest {
     }
 
     @Test
+    public void setMessagesShouldRejectMessageCreationWithNoMailbox() {
+        String messageCreationId = "creationId1337";
+        String fromAddress = USERNAME;
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": []" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        given()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        .when()
+            .post("/jmap")
+        .then()
+            .log().ifValidationFails()
+            .statusCode(200)
+            .body(NAME, equalTo("messagesSet"))
+            .body(ARGUMENTS + ".created", aMapWithSize(0))
+            .body(ARGUMENTS + ".notCreated", aMapWithSize(1))
+            .body(ARGUMENTS + ".notCreated", hasKey(messageCreationId))
+            .body(ARGUMENTS + ".notCreated." + messageCreationId + ".type", equalTo("invalidProperties"))
+            .body(ARGUMENTS + ".notCreated." + messageCreationId + ".description", equalTo("Message needs to be in at least one mailbox"))
+            .body(ARGUMENTS + ".notCreated." + messageCreationId + ".properties", contains("mailboxIds"));
+    }
+
+    @Test
     public void setMessagesShouldNotFailWhenSavingADraftInSeveralMailboxes() {
         String messageCreationId = "creationId1337";
         String fromAddress = USERNAME;

http://git-wip-us.apache.org/repos/asf/james-project/blob/b812aaad/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MessageHasNoMailboxException.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MessageHasNoMailboxException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MessageHasNoMailboxException.java
new file mode 100644
index 0000000..493a926
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MessageHasNoMailboxException.java
@@ -0,0 +1,24 @@
+/****************************************************************
+ * 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.exceptions;
+
+public class MessageHasNoMailboxException extends RuntimeException {
+    
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/b812aaad/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 7733b46..07c087c 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
@@ -33,6 +33,7 @@ import org.apache.james.jmap.exceptions.AttachmentsNotFoundException;
 import org.apache.james.jmap.exceptions.InvalidDraftKeywordsException;
 import org.apache.james.jmap.exceptions.InvalidMailboxForCreationException;
 import org.apache.james.jmap.exceptions.MailboxNotOwnedException;
+import org.apache.james.jmap.exceptions.MessageHasNoMailboxException;
 import org.apache.james.jmap.methods.ValueWithId.CreationMessageEntry;
 import org.apache.james.jmap.methods.ValueWithId.MessageWithId;
 import org.apache.james.jmap.model.CreationMessage;
@@ -111,6 +112,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private void handleCreate(CreationMessageEntry create, Builder responseBuilder, MailboxSession mailboxSession) {
         try {
+            assertAtLeastOneMailbox(create);
             assertIsUserOwnerOfMailboxes(create, mailboxSession);
             performCreate(create, responseBuilder, mailboxSession);
         } catch (MailboxSendingNotAllowedException e) {
@@ -147,6 +149,14 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
                         .description("Message creation is only supported in mailboxes with role Draft and Outbox")
                         .build());
 
+        } catch (MessageHasNoMailboxException e) {
+            responseBuilder.notCreated(create.getCreationId(),
+                    SetError.builder()
+                        .type("invalidProperties")
+                        .properties(MessageProperty.mailboxIds)
+                        .description("Message needs to be in at least one mailbox")
+                        .build());
+
         } catch (MailboxInvalidMessageCreationException e) {
             responseBuilder.notCreated(create.getCreationId(),
                     buildSetErrorFromValidationResult(create.getValue().validate()));
@@ -197,6 +207,12 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         }
     }
 
+    private void assertAtLeastOneMailbox(CreationMessageEntry entry) throws MailboxException {
+        if (entry.getValue().getMailboxIds().isEmpty()) {
+            throw new MessageHasNoMailboxException();
+        }
+    }
+
     private void sendMailViaOutbox(CreationMessageEntry entry, Builder responseBuilder, MailboxSession session) throws AttachmentsNotFoundException, MailboxException, MessagingException {
         validateArguments(entry, session);
         MessageWithId created = handleOutboxMessages(entry, session);


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


[3/3] james-project git commit: JAMES-2244 Allow draft creation out of Draft mailbox

Posted by bt...@apache.org.
JAMES-2244 Allow draft creation out of Draft mailbox


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/38acce23
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/38acce23
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/38acce23

Branch: refs/heads/master
Commit: 38acce2302a3851de89dfde618a8774c86aadf5c
Parents: 66f19b2
Author: benwa <bt...@linagora.com>
Authored: Tue Dec 12 16:06:21 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Dec 14 16:03:46 2017 +0700

----------------------------------------------------------------------
 .../integration/SetMessagesMethodTest.java      | 78 ++++++++++++++++++++
 .../james/jmap/methods/MessageAppender.java     | 16 +++-
 .../methods/SetMessagesCreationProcessor.java   | 11 ++-
 .../SetMessagesCreationProcessorTest.java       |  3 +
 4 files changed, 98 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/38acce23/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
index 3a6893f..196fb6a 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
@@ -1356,6 +1356,84 @@ public abstract class SetMessagesMethodTest {
     }
 
     @Test
+    public void setMessagesShouldCreateDraftInSeveralMailboxes() {
+        MailboxId mailboxId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+        String messageCreationId = "creationId1337";
+        String fromAddress = USERNAME;
+        String draftId = getDraftId(accessToken);
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + mailboxId.serialize() + "\", \"" + draftId + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        String messageId = given()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        .when()
+            .post("/jmap")
+        .then()
+            .extract()
+            .body()
+            .path(ARGUMENTS + ".created." + messageCreationId + ".id");
+
+        with()
+            .header("Authorization", accessToken.serialize())
+            .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, \"#0\"]]")
+            .post("/jmap")
+        .then()
+            .log().ifValidationFails()
+            .body(NAME, equalTo("messages"))
+            .body(ARGUMENTS + ".list", hasSize(1))
+            .body(ARGUMENTS + ".list[0].mailboxIds", containsInAnyOrder(mailboxId.serialize(), draftId));
+    }
+
+    @Test
+    public void setMessagesShouldAllowDraftCreationOutsideOfDraftMailbox() {
+        MailboxId mailboxId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+        String messageCreationId = "creationId1337";
+        String fromAddress = USERNAME;
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + mailboxId.serialize() + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        given()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        .when()
+            .post("/jmap")
+        .then()
+            .log().ifValidationFails()
+            .statusCode(200)
+            .body(NAME, equalTo("messagesSet"))
+            .body(ARGUMENTS + ".notCreated", aMapWithSize(0))
+            .body(ARGUMENTS + ".created", aMapWithSize(1))
+            .body(ARGUMENTS + ".created", hasKey(messageCreationId));
+    }
+
+    @Test
     public void setMessagesShouldRejectMessageCreationWithNoMailbox() {
         String messageCreationId = "creationId1337";
         String fromAddress = USERNAME;

http://git-wip-us.apache.org/repos/asf/james-project/blob/38acce23/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java
index 5ca9ab3..7bb2edc 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java
@@ -52,6 +52,7 @@ import org.slf4j.LoggerFactory;
 import com.github.fge.lambdas.Throwing;
 import com.github.fge.lambdas.functions.ThrowingFunction;
 import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 public class MessageAppender {
@@ -70,9 +71,10 @@ public class MessageAppender {
         this.mimeMessageConverter = mimeMessageConverter;
     }
 
-    public MessageFactory.MetaDataWithContent appendMessageInMailbox(CreationMessageEntry createdEntry,
-                                                                     List<MailboxId> targetMailboxes,
-                                                                     MailboxSession session) throws MailboxException {
+    public MessageFactory.MetaDataWithContent appendMessageInMailboxes(CreationMessageEntry createdEntry,
+                                                                       List<MailboxId> targetMailboxes,
+                                                                       MailboxSession session) throws MailboxException {
+        Preconditions.checkArgument(!targetMailboxes.isEmpty());
         ImmutableList<MessageAttachment> messageAttachments = getMessageAttachments(session, createdEntry.getValue().getAttachments());
         byte[] messageContent = mimeMessageConverter.convert(createdEntry, messageAttachments);
         SharedByteArrayInputStream content = new SharedByteArrayInputStream(messageContent);
@@ -81,7 +83,7 @@ public class MessageAppender {
         boolean notRecent = false;
         MessageManager mailbox = mailboxManager.getMailbox(targetMailboxes.get(0), session);
         ComposedMessageId message = mailbox.appendMessage(content, internalDate, session, notRecent, getFlags(createdEntry.getValue()));
-        if (targetMailboxes.size() > 0) {
+        if (targetMailboxes.size() > 1) {
             messageIdManager.setInMailboxes(message.getMessageId(), targetMailboxes, session);
         }
 
@@ -97,6 +99,12 @@ public class MessageAppender {
             .build();
     }
 
+    public MessageFactory.MetaDataWithContent appendMessageInMailbox(CreationMessageEntry createdEntry,
+                                                                       MailboxId targetMailbox,
+                                                                       MailboxSession session) throws MailboxException {
+        return appendMessageInMailboxes(createdEntry, ImmutableList.of(targetMailbox), session);
+    }
+
     private Flags getFlags(CreationMessage message) {
         return message.getOldKeyword()
                 .map(OldKeyword::asFlags)

http://git-wip-us.apache.org/repos/asf/james-project/blob/38acce23/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 b8f820b..00e4c1c 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
@@ -258,22 +258,22 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     }
 
     @VisibleForTesting void assertIsUserOwnerOfMailboxes(List<MailboxId> mailboxIds, MailboxSession session) throws MailboxNotOwnedException {
-        if (containsMailboxNotOwn(mailboxIds, session)) {
+        if (!allMailboxOwned(mailboxIds, session)) {
             throw new MailboxNotOwnedException();
         }
     }
 
-    private boolean containsMailboxNotOwn(List<MailboxId> mailboxIds, MailboxSession session) {
+    private boolean allMailboxOwned(List<MailboxId> mailboxIds, MailboxSession session) {
         FunctionChainer<MailboxId, MessageManager> findMailbox = Throwing.function(mailboxId -> mailboxManager.getMailbox(mailboxId, session));
         return mailboxIds.stream()
             .map(findMailbox.sneakyThrow())
             .map(Throwing.function(MessageManager::getMailboxPath))
-            .anyMatch(path -> !path.belongsTo(session));
+            .allMatch(path -> path.belongsTo(session));
     }
 
     private MessageWithId handleOutboxMessages(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MessagingException {
         assertUserIsSender(session, entry.getValue().getFrom());
-        MetaDataWithContent newMessage = messageAppender.appendMessageInMailbox(entry, toMailboxIds(entry), session);
+        MetaDataWithContent newMessage = messageAppender.appendMessageInMailboxes(entry, toMailboxIds(entry), session);
         Message jmapMessage = messageFactory.fromMetaDataWithContent(newMessage);
         Envelope envelope = Envelope.fromMessage(jmapMessage);
         messageSender.sendMessage(newMessage, envelope, session);
@@ -290,8 +290,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     }
 
     private MessageWithId handleDraftMessages(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MessagingException {
-        MessageManager draftMailbox = getMailboxWithRole(session, Role.DRAFTS).orElseThrow(() -> new MailboxNotFoundException(Role.DRAFTS.serialize()));
-        MetaDataWithContent newMessage = messageAppender.appendMessageInMailbox(entry, ImmutableList.of(draftMailbox.getId()), session);
+        MetaDataWithContent newMessage = messageAppender.appendMessageInMailboxes(entry, toMailboxIds(entry), session);
         Message jmapMessage = messageFactory.fromMetaDataWithContent(newMessage);
         return new ValueWithId.MessageWithId(entry.getCreationId(), jmapMessage);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/38acce23/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 ebdcc83..022be44 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
@@ -22,6 +22,7 @@ package org.apache.james.jmap.methods;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -289,6 +290,7 @@ public class SetMessagesCreationProcessorTest {
                     .build();
         when(mockedMailboxManager.getMailbox(any(MailboxId.class), any()))
             .thenReturn(outbox);
+        when(mockedMailboxIdFactory.fromString(anyString())).thenReturn(OUTBOX_ID);
 
         sut.process(notInOutboxCreationRequest, session);
 
@@ -306,6 +308,7 @@ public class SetMessagesCreationProcessorTest {
                 .build();
         when(mockedMailboxManager.getMailbox(any(MailboxId.class), any()))
             .thenReturn(drafts);
+        when(mockedMailboxIdFactory.fromString(anyString())).thenReturn(DRAFTS_ID);
         
         sut.process(createMessageInDrafts, session);
 


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