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 ad...@apache.org on 2017/11/15 11:15:42 UTC

[01/19] james-project git commit: JAMES-2214 Recipient validation should be done before sending

Repository: james-project
Updated Branches:
  refs/heads/master b539779b2 -> 5df4371bc


JAMES-2214 Recipient validation should be done before sending

This is required as recipients should not be validated when saving a draft, but only when sending it.


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

Branch: refs/heads/master
Commit: e3ffd2bf5fdb517a3c656b21259eb4d8fda77696
Parents: 4dbe064
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 09:56:49 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 17:58:15 2017 +0700

----------------------------------------------------------------------
 .../james/jmap/methods/MessageSender.java       | 16 +++++++++++++
 .../methods/SetMessagesCreationProcessor.java   | 25 ++------------------
 .../james/jmap/model/CreationMessage.java       |  5 ++++
 3 files changed, 23 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/e3ffd2bf/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
index dd94618..98e41d2 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
@@ -51,6 +51,7 @@ public class MessageSender {
     public void sendMessage(Message jmapMessage,
                             MessageFactory.MetaDataWithContent message,
                             MailboxSession session) throws MailboxException, MessagingException {
+        validateUserIsInSenders(jmapMessage, session);
         Mail mail = buildMessage(message, jmapMessage);
         try {
             MailMetadata metadata = new MailMetadata(jmapMessage.getId(), session.getUser().getUserName());
@@ -67,4 +68,19 @@ public class MessageSender {
             throw new MessagingException("error building message to send", e);
         }
     }
+
+    private void validateUserIsInSenders(Message message, MailboxSession session) throws MailboxSendingNotAllowedException {
+        List<String> allowedSenders = ImmutableList.of(session.getUser().getUserName());
+        if (!isAllowedFromAddress(message, allowedSenders)) {
+            throw new MailboxSendingNotAllowedException(allowedSenders);
+        }
+    }
+
+    private boolean isAllowedFromAddress(Message message, List<String> allowedFromMailAddresses) {
+        return message.getFrom()
+            .map(draftEmailer -> draftEmailer.getEmail()
+                .map(allowedFromMailAddresses::contains)
+                .orElse(false))
+            .orElse(false);
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e3ffd2bf/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 8fe1161..045bf37 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
@@ -67,7 +67,6 @@ import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
 
 
 public class SetMessagesCreationProcessor implements SetMessagesProcessor {
@@ -114,7 +113,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         try {
             validateImplementedFeature(create, mailboxSession);
             validateArguments(create, mailboxSession);
-            validateRights(create, mailboxSession);
+            validateIsUserOwnerOfMailboxes(create, mailboxSession);
             MessageWithId created = handleOutboxMessages(create, mailboxSession);
             responseBuilder.created(created.getCreationId(), created.getValue());
 
@@ -219,26 +218,6 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         return AttachmentId.from(attachment.getBlobId().getRawValue());
     }
 
-    private void validateRights(CreationMessageEntry entry, MailboxSession session) throws MailboxSendingNotAllowedException, MailboxRightsException {
-        validateUserIsInSenders(entry, session);
-        validateIsUserOwnerOfMailboxes(entry, session);
-    }
-
-    private void validateUserIsInSenders(CreationMessageEntry entry, MailboxSession session) throws MailboxSendingNotAllowedException {
-        List<String> allowedSenders = ImmutableList.of(session.getUser().getUserName());
-        if (!isAllowedFromAddress(entry.getValue(), allowedSenders)) {
-            throw new MailboxSendingNotAllowedException(allowedSenders);
-        }
-    }
-    
-    private boolean isAllowedFromAddress(CreationMessage creationMessage, List<String> allowedFromMailAddresses) {
-        return creationMessage.getFrom()
-                .map(draftEmailer -> draftEmailer.getEmail()
-                        .map(allowedFromMailAddresses::contains)
-                        .orElse(false))
-                .orElse(false);
-    }
-
     @VisibleForTesting void validateIsUserOwnerOfMailboxes(CreationMessageEntry entry, MailboxSession session) throws MailboxRightsException {
         if (containsMailboxNotOwn(entry.getValue().getMailboxIds(), session)) {
             throw new MailboxRightsException();
@@ -266,7 +245,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     
     private boolean isAppendToMailboxWithRole(Role role, CreationMessage entry, MailboxSession mailboxSession) throws MailboxException {
         return getMailboxWithRole(mailboxSession, role)
-                .map(entry::isIn)
+                .map(entry::isInOnly)
                 .orElse(false);
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e3ffd2bf/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 8bcbe4b..73bbf9d 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
@@ -370,6 +370,11 @@ public class CreationMessage {
     public boolean isIn(MessageManager mailbox) {
         return mailboxIds.contains(mailbox.getId().serialize());
     }
+
+    public boolean isInOnly(MessageManager mailbox) {
+        return isIn(mailbox)
+            && mailboxIds.size() == 1;
+    }
     
     @JsonDeserialize(builder = DraftEmailer.Builder.class)
     public static class DraftEmailer {


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


[04/19] james-project git commit: JAMES-2214 Correct error properties when saving with wrong attachments

Posted by ad...@apache.org.
JAMES-2214 Correct error properties when saving with wrong attachments

Before, messageIds was stated, which was wrong. That error properties was not tested.


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

Branch: refs/heads/master
Commit: 903ead093cda32982c9651ea5e12ca19592a1c22
Parents: b0f4d06
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 11:18:53 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 17:59:49 2017 +0700

----------------------------------------------------------------------
 .../james/jmap/methods/integration/SetMessagesMethodTest.java      | 1 +
 .../apache/james/jmap/methods/SetMessagesCreationProcessor.java    | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/903ead09/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 6e74189..54cf67b 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
@@ -2673,6 +2673,7 @@ public abstract class SetMessagesMethodTest {
             .body(NAME, equalTo("messagesSet"))
             .body(ARGUMENTS + ".notCreated", hasKey(messageCreationId))
             .body(notCreatedPath + ".type", equalTo("invalidProperties"))
+            .body(notCreatedPath + ".properties", contains("attachments"))
             .body(notCreatedPath + ".attachmentsNotFound", contains("brokenId1", "brokenId2"))
             .body(ARGUMENTS + ".created", aMapWithSize(0));
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/903ead09/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 2f12ebd..50407a2 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
@@ -124,7 +124,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
             responseBuilder.notCreated(create.getCreationId(), 
                     SetMessagesError.builder()
                         .type("invalidProperties")
-                        .properties(MessageProperty.mailboxIds)
+                        .properties(MessageProperty.attachments)
                         .attachmentsNotFound(e.getAttachmentIds())
                         .description("Attachment not found")
                         .build());


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


[18/19] james-project git commit: JAMES-2214 Improve Emailer and envelope design

Posted by ad...@apache.org.
JAMES-2214 Improve Emailer and envelope design


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

Branch: refs/heads/master
Commit: 5df4371bc064f7bdc764df65d7aaef538251afc3
Parents: 944643b
Author: benwa <bt...@linagora.com>
Authored: Tue Nov 14 16:49:10 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:46 2017 +0700

----------------------------------------------------------------------
 .../org/apache/james/jmap/model/Emailer.java    | 20 ++++++
 .../org/apache/james/jmap/model/Envelope.java   | 69 ++++++--------------
 .../org/apache/james/jmap/send/MailFactory.java | 10 +--
 3 files changed, 44 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/5df4371b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Emailer.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Emailer.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Emailer.java
index db6a701..5789939 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Emailer.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Emailer.java
@@ -22,6 +22,12 @@ package org.apache.james.jmap.model;
 import java.util.Objects;
 import java.util.Optional;
 
+import javax.mail.internet.AddressException;
+
+import org.apache.james.core.MailAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -29,10 +35,13 @@ import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
 
 @JsonDeserialize(builder = Emailer.Builder.class)
 public class Emailer {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(Emailer.class);
+
     public static Builder builder() {
         return new Builder();
     }
@@ -117,6 +126,17 @@ public class Emailer {
         return email;
     }
 
+    @JsonIgnore
+    public MailAddress toMailAddress() {
+        Preconditions.checkArgument(email.isPresent(), "eMailer mail address should be present when sending a mail using JMAP");
+        try {
+            return new MailAddress(email.get());
+        } catch (AddressException e) {
+            LOGGER.error("Invalid mail address", email);
+            throw Throwables.propagate(e);
+        }
+    }
+
     @Override
     public boolean equals(Object o) {
         if (o instanceof Emailer) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/5df4371b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Envelope.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Envelope.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Envelope.java
index e823aca..c4d80f9 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Envelope.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Envelope.java
@@ -22,78 +22,53 @@ package org.apache.james.jmap.model;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-import java.util.stream.Collectors;
-
-import javax.mail.internet.AddressException;
+import java.util.stream.Stream;
 
 import org.apache.james.core.MailAddress;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.james.util.StreamUtils;
 
+import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Throwables;
 
 public class Envelope {
-    private static final Logger LOGGER = LoggerFactory.getLogger(Envelope.class);
 
     public static Envelope fromMessage(Message jmapMessage) {
         MailAddress sender = jmapMessage.getFrom()
-            .map(Envelope::emailerToMailAddress)
+            .map(Emailer::toMailAddress)
             .orElseThrow(() -> new RuntimeException("Sender is mandatory"));
-        Set<MailAddress> to = emailersToMailAddressSet(jmapMessage.getTo());
-        Set<MailAddress> cc = emailersToMailAddressSet(jmapMessage.getCc());
-        Set<MailAddress> bcc = emailersToMailAddressSet(jmapMessage.getBcc());
 
-        return new Envelope(sender, to, cc, bcc);
+        Stream<MailAddress> to = emailersToMailAddresses(jmapMessage.getTo());
+        Stream<MailAddress> cc = emailersToMailAddresses(jmapMessage.getCc());
+        Stream<MailAddress> bcc = emailersToMailAddresses(jmapMessage.getBcc());
+
+        return new Envelope(sender,
+            StreamUtils.flatten(Stream.of(to, cc, bcc))
+                .collect(Guavate.toImmutableSet()));
     }
 
-    private static Set<MailAddress> emailersToMailAddressSet(List<Emailer> emailers) {
+    private static Stream<MailAddress> emailersToMailAddresses(List<Emailer> emailers) {
         return emailers.stream()
-            .map(Envelope::emailerToMailAddress)
-            .collect(Collectors.toSet());
+            .map(Emailer::toMailAddress);
     }
 
-    private static MailAddress emailerToMailAddress(Emailer emailer) {
-        Preconditions.checkArgument(emailer.getEmail().isPresent(), "eMailer mail address should be present when sending a mail using JMAP");
-        try {
-            return new MailAddress(emailer.getEmail().get());
-        } catch (AddressException e) {
-            LOGGER.error("Invalid mail address", emailer.getEmail());
-            throw Throwables.propagate(e);
-        }
-    }
 
     private final MailAddress from;
-    private final Set<MailAddress> to;
-    private final Set<MailAddress> cc;
-    private final Set<MailAddress> bcc;
+    private final Set<MailAddress> recipients;
 
-    private Envelope(MailAddress from, Set<MailAddress> to, Set<MailAddress> cc, Set<MailAddress> bcc) {
+    private Envelope(MailAddress from, Set<MailAddress> recipients) {
         Preconditions.checkNotNull(from);
-        Preconditions.checkNotNull(to);
-        Preconditions.checkNotNull(cc);
-        Preconditions.checkNotNull(bcc);
+        Preconditions.checkNotNull(recipients);
 
         this.from = from;
-        this.to = to;
-        this.cc = cc;
-        this.bcc = bcc;
+        this.recipients = recipients;
     }
 
     public MailAddress getFrom() {
         return from;
     }
 
-    public Set<MailAddress> getTo() {
-        return to;
-    }
-
-    public Set<MailAddress> getCc() {
-        return cc;
-    }
-
-    public Set<MailAddress> getBcc() {
-        return bcc;
+    public Set<MailAddress> getRecipients() {
+        return recipients;
     }
 
     @Override
@@ -102,15 +77,13 @@ public class Envelope {
             Envelope envelope = (Envelope) o;
 
             return Objects.equals(this.from, envelope.from)
-                && Objects.equals(this.to, envelope.to)
-                && Objects.equals(this.cc, envelope.cc)
-                && Objects.equals(this.bcc, envelope.bcc);
+                && Objects.equals(this.recipients, envelope.recipients);
         }
         return false;
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hash(from, to, cc, bcc);
+        return Objects.hash(from, recipients);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/5df4371b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
index 405bab1..3d156d3 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
@@ -21,15 +21,12 @@ package org.apache.james.jmap.send;
 
 import javax.mail.MessagingException;
 
-import org.apache.james.core.MailAddress;
 import org.apache.james.jmap.model.Envelope;
 import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent;
 import org.apache.james.server.core.MailImpl;
 import org.apache.mailet.Mail;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 
 public class MailFactory {
     
@@ -37,11 +34,10 @@ public class MailFactory {
     }
 
     public Mail build(MetaDataWithContent message, Envelope envelope) throws MessagingException {
-        ImmutableSet<MailAddress> recipients = Sets.union(
-            Sets.union(envelope.getTo(), envelope.getCc()),
-                envelope.getBcc()).immutableCopy();
         return new MailImpl(message.getMessageId().serialize(),
-            envelope.getFrom(), recipients, message.getContent());
+            envelope.getFrom(),
+            envelope.getRecipients(),
+            message.getContent());
     }
 
 }


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


[17/19] james-project git commit: JAMES-2214 Add an AttachmentManager exist method

Posted by ad...@apache.org.
JAMES-2214 Add an AttachmentManager exist method

 - More fluent API
 - Avoid retrieving full attachment content for existence checks


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

Branch: refs/heads/master
Commit: 90f3fb78a9319dd8cda03edd2452739c993551bf
Parents: 264ffd7
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 16:14:46 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:45 2017 +0700

----------------------------------------------------------------------
 .../java/org/apache/james/mailbox/AttachmentManager.java |  2 ++
 .../james/mailbox/store/StoreAttachmentManager.java      |  5 +++++
 .../org/apache/james/jmap/methods/AttachmentChecker.java | 11 ++---------
 .../apache/james/jmap/methods/AttachmentCheckerTest.java |  7 +++----
 4 files changed, 12 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/90f3fb78/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java
----------------------------------------------------------------------
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java
index fb2bc21..aabc4ed 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java
@@ -30,6 +30,8 @@ import org.apache.james.mailbox.model.MessageId;
 
 public interface AttachmentManager {
 
+    boolean exists(AttachmentId attachmentId, MailboxSession session) throws MailboxException;
+
     Attachment getAttachment(AttachmentId attachmentId, MailboxSession mailboxSession) throws MailboxException, AttachmentNotFoundException;
 
     List<Attachment> getAttachments(List<AttachmentId> attachmentIds, MailboxSession mailboxSession) throws MailboxException;

http://git-wip-us.apache.org/repos/asf/james-project/blob/90f3fb78/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java
index 6708d67..7552580 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java
@@ -53,6 +53,11 @@ public class StoreAttachmentManager implements AttachmentManager {
     }
 
     @Override
+    public boolean exists(AttachmentId attachmentId, MailboxSession session) throws MailboxException {
+        return userHasAccessToAttachment(attachmentId, session);
+    }
+
+    @Override
     public Attachment getAttachment(AttachmentId attachmentId, MailboxSession mailboxSession) throws MailboxException, AttachmentNotFoundException {
         if (!userHasAccessToAttachment(attachmentId, mailboxSession)) {
             throw new AttachmentNotFoundException(attachmentId.getId());

http://git-wip-us.apache.org/repos/asf/james-project/blob/90f3fb78/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/AttachmentChecker.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/AttachmentChecker.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/AttachmentChecker.java
index 77bbd62..24771b9 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/AttachmentChecker.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/AttachmentChecker.java
@@ -28,7 +28,6 @@ import org.apache.james.jmap.model.Attachment;
 import org.apache.james.jmap.model.BlobId;
 import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.exception.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.AttachmentId;
 
@@ -53,14 +52,8 @@ public class AttachmentChecker {
     }
 
     private List<BlobId> listAttachmentsNotFound(List<Attachment> attachments, MailboxSession session) throws MailboxException {
-        ThrowingPredicate<Attachment> notExists = attachment -> {
-            try {
-                attachmentManager.getAttachment(getAttachmentId(attachment), session);
-                return false;
-            } catch (AttachmentNotFoundException e) {
-                return true;
-            }
-        };
+        ThrowingPredicate<Attachment> notExists =
+            attachment -> !attachmentManager.exists(getAttachmentId(attachment), session);
         return attachments.stream()
             .filter(Throwing.predicate(notExists).sneakyThrow())
             .map(Attachment::getBlobId)

http://git-wip-us.apache.org/repos/asf/james-project/blob/90f3fb78/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
index dca2a44..c9df8e9 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
@@ -30,7 +30,6 @@ import org.apache.james.jmap.model.CreationMessage;
 import org.apache.james.jmap.model.CreationMessageId;
 import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.exception.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.mock.MockMailboxSession;
 import org.apache.james.mailbox.model.AttachmentId;
@@ -66,7 +65,7 @@ public class AttachmentCheckerTest {
     public void assertAttachmentsExistShouldThrowWhenUnknownBlobId() throws MailboxException {
         BlobId unknownBlobId = BlobId.of("unknownBlobId");
         AttachmentId unknownAttachmentId = AttachmentId.from(unknownBlobId.getRawValue());
-        when(attachmentManager.getAttachment(unknownAttachmentId, session)).thenThrow(new AttachmentNotFoundException(unknownBlobId.getRawValue()));
+        when(attachmentManager.exists(unknownAttachmentId, session)).thenReturn(false);
 
         assertThatThrownBy(() -> sut.assertAttachmentsExist(
             new ValueWithId.CreationMessageEntry(
@@ -86,8 +85,8 @@ public class AttachmentCheckerTest {
         AttachmentId unknownAttachmentId1 = AttachmentId.from(unknownBlobId1.getRawValue());
         AttachmentId unknownAttachmentId2 = AttachmentId.from(unknownBlobId2.getRawValue());
 
-        when(attachmentManager.getAttachment(unknownAttachmentId1, session)).thenThrow(new AttachmentNotFoundException(unknownBlobId1.getRawValue()));
-        when(attachmentManager.getAttachment(unknownAttachmentId2, session)).thenThrow(new AttachmentNotFoundException(unknownBlobId2.getRawValue()));
+        when(attachmentManager.exists(unknownAttachmentId1, session)).thenReturn(false);
+        when(attachmentManager.exists(unknownAttachmentId2, session)).thenReturn(false);
 
         assertThatThrownBy(() -> sut.assertAttachmentsExist(
             new ValueWithId.CreationMessageEntry(


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


[11/19] james-project git commit: PROTOCOLS-117 Add a stream helper

Posted by ad...@apache.org.
PROTOCOLS-117 Add a stream helper

We need a more readable way to concat (n) streams than chaining Stream.concat calls


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

Branch: refs/heads/master
Commit: 5c904e1ea778803c6d391c424f8ebe40317bb15b
Parents: 20a6c64
Author: benwa <bt...@linagora.com>
Authored: Wed Nov 8 11:31:26 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:45 2017 +0700

----------------------------------------------------------------------
 .../java/org/apache/james/util/StreamUtils.java | 34 +++++++++
 .../org/apache/james/util/StreamUtilsTest.java  | 80 ++++++++++++++++++++
 2 files changed, 114 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/5c904e1e/server/container/util-java8/src/main/java/org/apache/james/util/StreamUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/StreamUtils.java b/server/container/util-java8/src/main/java/org/apache/james/util/StreamUtils.java
new file mode 100644
index 0000000..f980802
--- /dev/null
+++ b/server/container/util-java8/src/main/java/org/apache/james/util/StreamUtils.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.Collection;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+public class StreamUtils {
+    public static  <T> Stream<T> flatten(Collection<Stream<T>> streams) {
+        return flatten(streams.stream());
+    }
+
+    public static  <T> Stream<T> flatten(Stream<Stream<T>> streams) {
+        return streams.flatMap(Function.identity());
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c904e1e/server/container/util-java8/src/test/java/org/apache/james/util/StreamUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/StreamUtilsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/StreamUtilsTest.java
new file mode 100644
index 0000000..c14cd4c
--- /dev/null
+++ b/server/container/util-java8/src/test/java/org/apache/james/util/StreamUtilsTest.java
@@ -0,0 +1,80 @@
+/****************************************************************
+ * 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.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.stream.Stream;
+
+import org.junit.Test;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
+
+import com.github.steveash.guavate.Guavate;
+
+public class StreamUtilsTest {
+
+    @Test
+    public void flattenShouldReturnEmptyWhenEmptyStreams() {
+        assertThat(
+            StreamUtils.<Integer>flatten(ImmutableList.of())
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void flattenShouldPreserveSingleStreams() {
+        assertThat(
+            StreamUtils.flatten(ImmutableList.of(
+                Stream.of(1, 2, 3)))
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+    @Test
+    public void flattenShouldMergeSeveralStreamsTogether() {
+        assertThat(
+            StreamUtils.flatten(ImmutableList.of(
+                Stream.of(1, 2, 3),
+                Stream.of(4, 5)))
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3, 4, 5);
+    }
+
+    @Test
+    public void flattenShouldAcceptEmptyStreams() {
+        assertThat(
+            StreamUtils.flatten(ImmutableList.of(
+                Stream.of()))
+                .collect(Guavate.toImmutableList()))
+            .isEmpty();
+    }
+
+    @Test
+    public void flattenShouldMergeEmptyStreamsWithOtherData() {
+        assertThat(
+            StreamUtils.flatten(ImmutableList.of(
+                Stream.of(1, 2),
+                Stream.of(),
+                Stream.of(3)))
+                .collect(Guavate.toImmutableList()))
+            .containsExactly(1, 2, 3);
+    }
+
+}
\ No newline at end of file


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


[14/19] james-project git commit: JAMES-2214 Attachment checking should be extracted from SetMessagesCreationProcessor

Posted by ad...@apache.org.
JAMES-2214 Attachment checking should be extracted from SetMessagesCreationProcessor


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

Branch: refs/heads/master
Commit: 20a6c64ee291fb22f8418ac81d0ca98dd82d809f
Parents: 9f1d767
Author: benwa <bt...@linagora.com>
Authored: Tue Nov 14 10:51:41 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:45 2017 +0700

----------------------------------------------------------------------
 .../jmap/methods/AttachmentCheckerTest.java     | 61 ++++++++++++++++++++
 1 file changed, 61 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/20a6c64e/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
index c9df8e9..f34eff0 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
@@ -79,6 +79,22 @@ public class AttachmentCheckerTest {
     }
 
     @Test
+    public void assertAttachmentsExistShouldNotThrowWhenAttachmentExists() throws Exception {
+        BlobId blobId = BlobId.of("unknownBlobId");
+        AttachmentId attachmentId = AttachmentId.from(blobId.getRawValue());
+        when(attachmentManager.exists(attachmentId, session)).thenReturn(true);
+
+        sut.assertAttachmentsExist(
+            new ValueWithId.CreationMessageEntry(
+                creationMessageId,
+                creationMessageBuilder.attachments(
+                    Attachment.builder().size(12L).type("image/jpeg").blobId(blobId).build())
+                    .build()
+            ),
+            session);
+    }
+
+    @Test
     public void assertAttachmentsExistShouldThrowWhenUnknownBlobIds() throws MailboxException {
         BlobId unknownBlobId1 = BlobId.of("unknownBlobId1");
         BlobId unknownBlobId2 = BlobId.of("unknownBlobId2");
@@ -101,4 +117,49 @@ public class AttachmentCheckerTest {
             .matches(e -> ((AttachmentsNotFoundException)e).getAttachmentIds().containsAll(ImmutableSet.of(unknownBlobId1, unknownBlobId2)));
     }
 
+    @Test
+    public void assertAttachmentsExistShouldNotThrowWhenKnownBlobIds() throws Exception {
+        BlobId blobId1 = BlobId.of("unknownBlobId1");
+        BlobId blobId2 = BlobId.of("unknownBlobId2");
+        AttachmentId attachmentId1 = AttachmentId.from(blobId1.getRawValue());
+        AttachmentId attachmentId2 = AttachmentId.from(blobId2.getRawValue());
+
+        when(attachmentManager.exists(attachmentId1, session)).thenReturn(true);
+        when(attachmentManager.exists(attachmentId2, session)).thenReturn(true);
+
+        sut.assertAttachmentsExist(
+            new ValueWithId.CreationMessageEntry(
+                creationMessageId,
+                creationMessageBuilder.attachments(
+                    Attachment.builder().size(12L).type("image/jpeg").blobId(blobId1).build(),
+                    Attachment.builder().size(23L).type("image/git").blobId(blobId2).build())
+                    .build()
+            ),
+            session);
+    }
+
+    @Test
+    public void assertAttachmentsExistShouldThrowWhenAtLeastOneUnknownBlobId() throws MailboxException {
+        BlobId blobId1 = BlobId.of("unknownBlobId1");
+        BlobId unknownBlobId2 = BlobId.of("unknownBlobId2");
+        AttachmentId attachmentId1 = AttachmentId.from(blobId1.getRawValue());
+        AttachmentId unknownAttachmentId2 = AttachmentId.from(unknownBlobId2.getRawValue());
+
+        when(attachmentManager.exists(attachmentId1, session)).thenReturn(true);
+        when(attachmentManager.exists(unknownAttachmentId2, session)).thenReturn(false);
+
+        assertThatThrownBy(() -> sut.assertAttachmentsExist(
+            new ValueWithId.CreationMessageEntry(
+                creationMessageId,
+                creationMessageBuilder.attachments(
+                    Attachment.builder().size(12L).type("image/jpeg").blobId(blobId1).build(),
+                    Attachment.builder().size(23L).type("image/git").blobId(unknownBlobId2).build())
+                    .build()
+            ),
+            session))
+            .isInstanceOf(AttachmentsNotFoundException.class)
+            .matches(e -> ((AttachmentsNotFoundException)e).getAttachmentIds()
+                .containsAll(ImmutableSet.of(unknownBlobId2)));
+    }
+
 }
\ No newline at end of file


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


[05/19] james-project git commit: JAMES-2214 Fix mailbox not found invalid lambda in SetMessages::create

Posted by ad...@apache.org.
JAMES-2214 Fix mailbox not found invalid lambda in SetMessages::create


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

Branch: refs/heads/master
Commit: f85b5c6b4c47af63c66c09adce121506277a56ab
Parents: 903ead0
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 11:43:03 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 17:59:49 2017 +0700

----------------------------------------------------------------------
 .../integration/SetMessagesMethodTest.java      | 45 ++++++++++++++++++--
 .../methods/SetMessagesCreationProcessor.java   |  6 ++-
 .../SetMessagesCreationProcessorTest.java       |  4 ++
 3 files changed, 50 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/f85b5c6b/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 54cf67b..3508e65 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
@@ -120,10 +120,13 @@ public abstract class SetMessagesMethodTest {
     private static final String USERS_DOMAIN = "domain.tld";
     private static final String USERNAME = "username@" + USERS_DOMAIN;
     private static final String PASSWORD = "password";
+    private static final String BOB = "bob@" + USERS_DOMAIN;
+    private static final String BOB_PASSWORD = "bobPassword";
     private static final MailboxPath USER_MAILBOX = MailboxPath.forUser(USERNAME, "mailbox");
     private static final String NOT_UPDATED = ARGUMENTS + ".notUpdated";
 
     private ConditionFactory calmlyAwait;
+    private AccessToken bobAccessToken;
 
     protected abstract GuiceJamesServer createJmapServer();
 
@@ -158,8 +161,10 @@ public abstract class SetMessagesMethodTest {
 
         dataProbe.addDomain(USERS_DOMAIN);
         dataProbe.addUser(USERNAME, PASSWORD);
+        dataProbe.addUser(BOB, BOB_PASSWORD);
         mailboxProbe.createMailbox("#private", USERNAME, DefaultMailboxes.INBOX);
         accessToken = HttpJmapAuthentication.authenticateJamesUser(baseUri(), USERNAME, PASSWORD);
+        bobAccessToken = HttpJmapAuthentication.authenticateJamesUser(baseUri(), BOB, BOB_PASSWORD);
 
         mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, DefaultMailboxes.OUTBOX);
         mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, DefaultMailboxes.TRASH);
@@ -1182,6 +1187,40 @@ public abstract class SetMessagesMethodTest {
     }
 
     @Test
+    public void setMessagesShouldReturnValidErrorWhenMailboxNotFound() {
+        String messageCreationId = "creationId1337";
+        String fromAddress = USERNAME;
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+            "        \"subject\": \"\"," +
+            "        \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        given()
+            .header("Authorization", bobAccessToken.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." + messageCreationId + ".type", equalTo("error"))
+            .body(ARGUMENTS + ".notCreated." + messageCreationId + ".description", endsWith("can not be found"));
+    }
+
+    @Test
     public void setMessagesShouldReturnCreatedMessageWithNonASCIICharactersInSubjectWhenPresent() {
         String messageCreationId = "creationId1337";
         String fromAddress = USERNAME;
@@ -1325,6 +1364,7 @@ public abstract class SetMessagesMethodTest {
             .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].keywords.$Flagged", equalTo(true))
             ;
     }
+
     @Test
     public void setMessagesShouldSupportArbitraryMessageId() {
         String messageCreationId = "1717fcd1-603e-44a5-b2a6-1234dbcd5723";
@@ -1890,11 +1930,10 @@ public abstract class SetMessagesMethodTest {
         dataProbe.addUser(recipientAddress, password);
         mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, recipientAddress, DefaultMailboxes.INBOX);
 
-        String bccAddress = "bob" + "@" + USERS_DOMAIN;
-        dataProbe.addUser(bccAddress, password);
+        String bccAddress = BOB;
         mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, bccAddress, DefaultMailboxes.INBOX);
         await();
-        AccessToken bccToken = HttpJmapAuthentication.authenticateJamesUser(baseUri(), bccAddress, password);
+        AccessToken bccToken = HttpJmapAuthentication.authenticateJamesUser(baseUri(), BOB, BOB_PASSWORD);
 
         String messageCreationId = "creationId1337";
         String fromAddress = USERNAME;

http://git-wip-us.apache.org/repos/asf/james-project/blob/f85b5c6b/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 50407a2..870235c 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
@@ -57,6 +57,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.github.fge.lambdas.Throwing;
+import com.github.fge.lambdas.functions.FunctionChainer;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
@@ -105,9 +106,9 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private void handleCreate(CreationMessageEntry create, Builder responseBuilder, MailboxSession mailboxSession) {
         try {
+            validateIsUserOwnerOfMailboxes(create, mailboxSession);
             validateImplementedFeature(create, mailboxSession);
             validateArguments(create, mailboxSession);
-            validateIsUserOwnerOfMailboxes(create, mailboxSession);
             MessageWithId created = handleOutboxMessages(create, mailboxSession);
             responseBuilder.created(created.getCreationId(), created.getValue());
 
@@ -190,9 +191,10 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     }
 
     private boolean containsMailboxNotOwn(List<String> mailboxIds, MailboxSession session) {
+        FunctionChainer<MailboxId, MessageManager> findMailbox = Throwing.function(mailboxId -> mailboxManager.getMailbox(mailboxId, session));
         return mailboxIds.stream()
             .map(mailboxIdFactory::fromString)
-            .map(Throwing.function(mailboxId -> mailboxManager.getMailbox(mailboxId, session)))
+            .map(findMailbox.sneakyThrow())
             .map(Throwing.function(MessageManager::getMailboxPath))
             .anyMatch(path -> !session.getUser().isSameUser(path.getUser()));
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f85b5c6b/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 2857b1e..1ef68ea 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
@@ -62,6 +62,7 @@ import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.mock.MockMailboxSession;
 import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxId.Factory;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageId;
@@ -286,6 +287,8 @@ public class SetMessagesCreationProcessorTest {
                             creationMessageBuilder.mailboxId("any-id-but-outbox-id")
                         .build())
                     .build();
+        when(mockedMailboxManager.getMailbox(any(MailboxId.class), any()))
+            .thenReturn(outbox);
 
         sut.process(notInOutboxCreationRequest, session);
 
@@ -320,6 +323,7 @@ public class SetMessagesCreationProcessorTest {
                 .create(
                         creationMessageId, creationMessageBuilder.mailboxId(DRAFTS_ID.serialize()).build())
                 .build();
+        when(mockedMailboxManager.getMailbox(any(MailboxId.class), any())).thenReturn(drafts);
         sut.process(createMessageInDrafts, session);
 
         // Then


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


[16/19] james-project git commit: JAMES-2214 Rename ambiguous and misleading MailboxNotImplementedException

Posted by ad...@apache.org.
JAMES-2214 Rename ambiguous and misleading MailboxNotImplementedException

  MailboxNotImplementedException and the "Not yet implemented" message is misleading.

  JMAP spec does not support, whatever version you take, saving messages in other mailboxes than Outbox or Draft.

  The error message name should explain that the given mailboxes were invalid. Moreover, the error message should explain which state was not met by the provided mailboxes.


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

Branch: refs/heads/master
Commit: 8ad6ba63c84042619395ec8e10cfc09583740784
Parents: 1e8d057
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 13:08:14 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:45 2017 +0700

----------------------------------------------------------------------
 .../integration/SetMessagesMethodTest.java      |  8 +++---
 .../InvalidMailboxForCreationException.java     | 30 ++++++++++++++++++++
 .../methods/MailboxNotImplementedException.java | 30 --------------------
 .../methods/SetMessagesCreationProcessor.java   |  9 +++---
 4 files changed, 39 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/8ad6ba63/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 13e1da4..97fbf15 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
@@ -1439,11 +1439,11 @@ public abstract class SetMessagesMethodTest {
             .body(ARGUMENTS + ".notCreated", hasKey(messageCreationId))
             .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].type", equalTo("invalidProperties"))
             .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].properties", contains("mailboxIds"))
-            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", equalTo("Not yet implemented"));
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", equalTo("Message creation is only supported in mailboxes with role Draft and Outbox"));
     }
 
     @Test
-    public void setMessagesShouldBeCompatibleWithIsDraftProperty() {
+    public void setMessageShouldAllowDraftCreationWhenUsingIsDraftProperty() {
         String messageCreationId = "creationId1337";
         String fromAddress = USERNAME;
         String requestBody = "[" +
@@ -1511,7 +1511,7 @@ public abstract class SetMessagesMethodTest {
             .body(ARGUMENTS + ".notCreated", hasKey(messageCreationId))
             .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].type", equalTo("invalidProperties"))
             .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].properties", contains("mailboxIds"))
-            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", equalTo("Not yet implemented"));
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", equalTo("Message creation is only supported in mailboxes with role Draft and Outbox"));
     }
 
     @Test
@@ -2645,7 +2645,7 @@ public abstract class SetMessagesMethodTest {
             .statusCode(200)
             .body(ARGUMENTS + ".notCreated", hasKey(messageCreationId))
             .body(notCreatedMessage + ".type", equalTo("invalidProperties"))
-            .body(notCreatedMessage + ".description", equalTo("Not yet implemented"))
+            .body(notCreatedMessage + ".description", equalTo("Message creation is only supported in mailboxes with role Draft and Outbox"))
             .body(ARGUMENTS + ".created", aMapWithSize(0));
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/8ad6ba63/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/InvalidMailboxForCreationException.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/InvalidMailboxForCreationException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/InvalidMailboxForCreationException.java
new file mode 100644
index 0000000..bd1ea0b
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/InvalidMailboxForCreationException.java
@@ -0,0 +1,30 @@
+/****************************************************************
+ * 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;
+
+import org.apache.james.mailbox.exception.MailboxException;
+
+public class InvalidMailboxForCreationException extends MailboxException {
+
+    public InvalidMailboxForCreationException(String message) {
+        super(message);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/8ad6ba63/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxNotImplementedException.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxNotImplementedException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxNotImplementedException.java
deleted file mode 100644
index a7da6d4..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxNotImplementedException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/****************************************************************
- * 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.methods;
-
-import org.apache.james.mailbox.exception.MailboxException;
-
-public class MailboxNotImplementedException extends MailboxException {
-
-    public MailboxNotImplementedException(String message) {
-        super(message);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/8ad6ba63/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 71e3a11..4b0e38b 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
@@ -31,6 +31,7 @@ import javax.mail.MessagingException;
 
 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.methods.ValueWithId.CreationMessageEntry;
 import org.apache.james.jmap.methods.ValueWithId.MessageWithId;
@@ -137,12 +138,12 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
                         .description("Attachment not found")
                         .build());
             
-        } catch (MailboxNotImplementedException e) {
+        } catch (InvalidMailboxForCreationException e) {
             responseBuilder.notCreated(create.getCreationId(), 
                     SetError.builder()
                         .type("invalidProperties")
                         .properties(MessageProperty.mailboxIds)
-                        .description("Not yet implemented")
+                        .description("Message creation is only supported in mailboxes with role Draft and Outbox")
                         .build());
 
         } catch (MailboxInvalidMessageCreationException e) {
@@ -175,13 +176,13 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         }
     }
     
-    private void performCreate(CreationMessageEntry entry, Builder responseBuilder, MailboxSession session) throws MailboxException, MailboxNotImplementedException, MessagingException, AttachmentsNotFoundException {
+    private void performCreate(CreationMessageEntry entry, Builder responseBuilder, MailboxSession session) throws MailboxException, InvalidMailboxForCreationException, MessagingException, AttachmentsNotFoundException {
         if (isAppendToMailboxWithRole(Role.DRAFTS, entry.getValue(), session)) {
             saveDraft(entry, responseBuilder, session);
         } else if (isAppendToMailboxWithRole(Role.OUTBOX, entry.getValue(), session)) {
             sendMailViaOutbox(entry, responseBuilder, session);
         } else {
-            throw new MailboxNotImplementedException("The only implemented feature is sending via outbox and draft saving");
+            throw new InvalidMailboxForCreationException("The only implemented feature is sending via outbox and draft saving");
         }
     }
 


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


[19/19] james-project git commit: PROTOCOLS-117 Use StreamUtils::flatten

Posted by ad...@apache.org.
PROTOCOLS-117 Use StreamUtils::flatten


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

Branch: refs/heads/master
Commit: 944643b6b21ec75ff803b2788205772a94acd7cd
Parents: 5c904e1
Author: benwa <bt...@linagora.com>
Authored: Wed Nov 8 11:35:04 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:46 2017 +0700

----------------------------------------------------------------------
 mdn/src/main/java/org/apache/james/mdn/MDNReport.java | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/944643b6/mdn/src/main/java/org/apache/james/mdn/MDNReport.java
----------------------------------------------------------------------
diff --git a/mdn/src/main/java/org/apache/james/mdn/MDNReport.java b/mdn/src/main/java/org/apache/james/mdn/MDNReport.java
index 2d84c86..2878bfa 100644
--- a/mdn/src/main/java/org/apache/james/mdn/MDNReport.java
+++ b/mdn/src/main/java/org/apache/james/mdn/MDNReport.java
@@ -36,6 +36,7 @@ import org.apache.james.mdn.fields.OriginalRecipient;
 import org.apache.james.mdn.fields.ReportingUserAgent;
 import org.apache.james.mdn.fields.Text;
 import org.apache.james.util.OptionalUtils;
+import org.apache.james.util.StreamUtils;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
@@ -233,9 +234,10 @@ public class MDNReport {
         Stream<Optional<? extends Field>> extentions =
             extensionFields.stream().map(Optional::of);
 
-        return Stream.concat(
-            definedFields,
-            Stream.concat(errors,
+        return StreamUtils.flatten(
+            Stream.of(
+                definedFields,
+                errors,
                 extentions))
             .flatMap(OptionalUtils::toStream)
             .map(Field::formattedValue)


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


[10/19] james-project git commit: JAMES-2214 Make calls to MailFactory less ambiguous by only requiring an Envelope and not a full JMAP Message

Posted by ad...@apache.org.
JAMES-2214 Make calls to MailFactory less ambiguous by only requiring an Envelope and not a full JMAP Message


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

Branch: refs/heads/master
Commit: a04c071c42926fb917f7df127d8dde2b69252e5e
Parents: 2b22852
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 16:48:48 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:45 2017 +0700

----------------------------------------------------------------------
 .../james/jmap/methods/MessageSender.java       |  28 ++---
 .../methods/SetMessagesCreationProcessor.java   |   4 +-
 .../org/apache/james/jmap/model/Envelope.java   | 116 +++++++++++++++++++
 .../org/apache/james/jmap/send/MailFactory.java |  46 ++------
 .../apache/james/jmap/send/MailFactoryTest.java |   7 +-
 5 files changed, 142 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/a04c071c/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
index 6a1a089..8d86355 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
@@ -24,7 +24,7 @@ import java.io.IOException;
 import javax.inject.Inject;
 import javax.mail.MessagingException;
 
-import org.apache.james.jmap.model.Message;
+import org.apache.james.jmap.model.Envelope;
 import org.apache.james.jmap.model.MessageFactory;
 import org.apache.james.jmap.send.MailFactory;
 import org.apache.james.jmap.send.MailMetadata;
@@ -44,39 +44,31 @@ public class MessageSender {
         this.mailFactory = mailFactory;
     }
 
-    public void sendMessage(Message jmapMessage,
-                            MessageFactory.MetaDataWithContent message,
+    public void sendMessage(MessageFactory.MetaDataWithContent message,
+                            Envelope envelope,
                             MailboxSession session) throws MailboxException, MessagingException {
-        assertUserIsInSenders(jmapMessage, session);
-        Mail mail = buildMessage(message, jmapMessage);
+        assertUserIsInSenders(envelope, session);
+        Mail mail = buildMessage(message, envelope);
         try {
-            MailMetadata metadata = new MailMetadata(jmapMessage.getId(), session.getUser().getUserName());
+            MailMetadata metadata = new MailMetadata(message.getMessageId(), session.getUser().getUserName());
             mailSpool.send(mail, metadata);
         } finally {
             LifecycleUtil.dispose(mail);
         }
     }
 
-    private Mail buildMessage(MessageFactory.MetaDataWithContent message, Message jmapMessage) throws MessagingException {
+    private Mail buildMessage(MessageFactory.MetaDataWithContent message, Envelope envelope) throws MessagingException {
         try {
-            return mailFactory.build(message, jmapMessage);
+            return mailFactory.build(message, envelope);
         } catch (IOException e) {
             throw new MessagingException("error building message to send", e);
         }
     }
 
-    private void assertUserIsInSenders(Message message, MailboxSession session) throws MailboxSendingNotAllowedException {
+    private void assertUserIsInSenders(Envelope envelope, MailboxSession session) throws MailboxSendingNotAllowedException {
         String allowedSender = session.getUser().getUserName();
-        if (!isAllowedFromAddress(message, allowedSender)) {
+        if (!session.getUser().isSameUser(envelope.getFrom().asString())) {
             throw new MailboxSendingNotAllowedException(allowedSender);
         }
     }
-
-    private boolean isAllowedFromAddress(Message message, String allowedFromMailAddress) {
-        return message.getFrom()
-            .map(draftEmailer -> draftEmailer.getEmail()
-                .map(allowedFromMailAddress::equals)
-                .orElse(false))
-            .orElse(false);
-    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/a04c071c/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 19dc981..4bb43dc 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
@@ -36,6 +36,7 @@ import org.apache.james.jmap.exceptions.MailboxNotOwnedException;
 import org.apache.james.jmap.methods.ValueWithId.CreationMessageEntry;
 import org.apache.james.jmap.methods.ValueWithId.MessageWithId;
 import org.apache.james.jmap.model.CreationMessage;
+import org.apache.james.jmap.model.Envelope;
 import org.apache.james.jmap.model.Keyword;
 import org.apache.james.jmap.model.Message;
 import org.apache.james.jmap.model.MessageFactory;
@@ -235,7 +236,8 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         MessageManager outbox = getMailboxWithRole(session, Role.OUTBOX).orElseThrow(() -> new MailboxNotFoundException(Role.OUTBOX.serialize()));
         MetaDataWithContent newMessage = messageAppender.appendMessageInMailbox(entry, outbox, session);
         Message jmapMessage = messageFactory.fromMetaDataWithContent(newMessage);
-        messageSender.sendMessage(jmapMessage, newMessage, session);
+        Envelope envelope = Envelope.fromMessage(jmapMessage);
+        messageSender.sendMessage(newMessage, envelope, session);
         return new ValueWithId.MessageWithId(entry.getCreationId(), jmapMessage);
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/a04c071c/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Envelope.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Envelope.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Envelope.java
new file mode 100644
index 0000000..e823aca
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Envelope.java
@@ -0,0 +1,116 @@
+/****************************************************************
+ * 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.model;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.mail.internet.AddressException;
+
+import org.apache.james.core.MailAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+
+public class Envelope {
+    private static final Logger LOGGER = LoggerFactory.getLogger(Envelope.class);
+
+    public static Envelope fromMessage(Message jmapMessage) {
+        MailAddress sender = jmapMessage.getFrom()
+            .map(Envelope::emailerToMailAddress)
+            .orElseThrow(() -> new RuntimeException("Sender is mandatory"));
+        Set<MailAddress> to = emailersToMailAddressSet(jmapMessage.getTo());
+        Set<MailAddress> cc = emailersToMailAddressSet(jmapMessage.getCc());
+        Set<MailAddress> bcc = emailersToMailAddressSet(jmapMessage.getBcc());
+
+        return new Envelope(sender, to, cc, bcc);
+    }
+
+    private static Set<MailAddress> emailersToMailAddressSet(List<Emailer> emailers) {
+        return emailers.stream()
+            .map(Envelope::emailerToMailAddress)
+            .collect(Collectors.toSet());
+    }
+
+    private static MailAddress emailerToMailAddress(Emailer emailer) {
+        Preconditions.checkArgument(emailer.getEmail().isPresent(), "eMailer mail address should be present when sending a mail using JMAP");
+        try {
+            return new MailAddress(emailer.getEmail().get());
+        } catch (AddressException e) {
+            LOGGER.error("Invalid mail address", emailer.getEmail());
+            throw Throwables.propagate(e);
+        }
+    }
+
+    private final MailAddress from;
+    private final Set<MailAddress> to;
+    private final Set<MailAddress> cc;
+    private final Set<MailAddress> bcc;
+
+    private Envelope(MailAddress from, Set<MailAddress> to, Set<MailAddress> cc, Set<MailAddress> bcc) {
+        Preconditions.checkNotNull(from);
+        Preconditions.checkNotNull(to);
+        Preconditions.checkNotNull(cc);
+        Preconditions.checkNotNull(bcc);
+
+        this.from = from;
+        this.to = to;
+        this.cc = cc;
+        this.bcc = bcc;
+    }
+
+    public MailAddress getFrom() {
+        return from;
+    }
+
+    public Set<MailAddress> getTo() {
+        return to;
+    }
+
+    public Set<MailAddress> getCc() {
+        return cc;
+    }
+
+    public Set<MailAddress> getBcc() {
+        return bcc;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof Envelope) {
+            Envelope envelope = (Envelope) o;
+
+            return Objects.equals(this.from, envelope.from)
+                && Objects.equals(this.to, envelope.to)
+                && Objects.equals(this.cc, envelope.cc)
+                && Objects.equals(this.bcc, envelope.bcc);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(from, to, cc, bcc);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/a04c071c/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
index 4fa46c5..7db6a9b 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
@@ -20,60 +20,30 @@
 package org.apache.james.jmap.send;
 
 import java.io.IOException;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
 
 import javax.mail.MessagingException;
-import javax.mail.internet.AddressException;
 
-import org.apache.james.server.core.MailImpl;
-import org.apache.james.jmap.model.Emailer;
-import org.apache.james.jmap.model.Message;
+import org.apache.james.core.MailAddress;
+import org.apache.james.jmap.model.Envelope;
 import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent;
+import org.apache.james.server.core.MailImpl;
 import org.apache.mailet.Mail;
-import org.apache.james.core.MailAddress;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 
 public class MailFactory {
-    private static final Logger LOGGER = LoggerFactory.getLogger(MailFactory.class);
     
     @VisibleForTesting MailFactory() {
     }
 
-    public Mail build(MetaDataWithContent message, Message jmapMessage) throws MessagingException, IOException {
-        MailAddress sender = jmapMessage.getFrom()
-                .map(this::emailerToMailAddress)
-                .orElseThrow(() -> new RuntimeException("Sender is mandatory"));
-        Set<MailAddress> to = emailersToMailAddressSet(jmapMessage.getTo());
-        Set<MailAddress> cc = emailersToMailAddressSet(jmapMessage.getCc());
-        Set<MailAddress> bcc = emailersToMailAddressSet(jmapMessage.getBcc());
+    public Mail build(MetaDataWithContent message, Envelope envelope) throws MessagingException, IOException {
         ImmutableSet<MailAddress> recipients = Sets.union(
-                Sets.union(to, cc),
-                bcc).immutableCopy();
-        return new MailImpl(jmapMessage.getId().serialize(), sender, recipients, message.getContent());
+            Sets.union(envelope.getTo(), envelope.getCc()),
+                envelope.getBcc()).immutableCopy();
+        return new MailImpl(message.getMessageId().serialize(),
+            envelope.getFrom(), recipients, message.getContent());
     }
 
-    private MailAddress emailerToMailAddress(Emailer emailer) {
-        Preconditions.checkArgument(emailer.getEmail().isPresent(), "eMailer mail address should be present when sending a mail using JMAP");
-        try {
-            return new MailAddress(emailer.getEmail().get());
-        } catch (AddressException e) {
-            LOGGER.error("Invalid mail address", emailer.getEmail());
-            throw Throwables.propagate(e);
-        }
-    }
-
-    private Set<MailAddress> emailersToMailAddressSet(List<Emailer> emailers) {
-        return emailers.stream()
-            .map(this::emailerToMailAddress)
-            .collect(Collectors.toSet());
-    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/a04c071c/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
index 501e9c1..7dfffc1 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
@@ -29,6 +29,7 @@ import java.util.Collection;
 import javax.mail.util.SharedByteArrayInputStream;
 
 import org.apache.james.core.MailAddress;
+import org.apache.james.jmap.model.Envelope;
 import org.apache.james.jmap.model.Keyword;
 import org.apache.james.jmap.model.Keywords;
 import org.apache.james.jmap.model.Message;
@@ -57,6 +58,7 @@ public class MailFactoryTest {
     private MailFactory testee;
     private MetaDataWithContent message;
     private Message jmapMessage;
+    private Envelope envelope;
 
     @Before
     public void init() throws MailboxException {
@@ -88,11 +90,12 @@ public class MailFactoryTest {
         when(blobManager.toBlobId(any(MessageId.class))).thenReturn(BlobId.fromString("fake"));
         MessageFactory messageFactory = new MessageFactory(blobManager, messagePreview, messageContentExtractor, htmlTextExtractor);
         jmapMessage = messageFactory.fromMetaDataWithContent(message);
+        envelope = Envelope.fromMessage(jmapMessage);
     }
 
     @Test(expected=NullPointerException.class)
     public void buildMailShouldThrowWhenNullMailboxMessage() throws Exception {
-        testee.build(null, jmapMessage);
+        testee.build(null, envelope);
     }
 
     @Test(expected=NullPointerException.class)
@@ -110,7 +113,7 @@ public class MailFactoryTest {
                 new MailAddress("2@example.com"),
                 new MailAddress("4@example.com"));
         
-        Mail actual = testee.build(message, jmapMessage);
+        Mail actual = testee.build(message, envelope);
         
         assertThat(actual.getName()).isEqualTo(expectedName);
         assertThat(actual.getSender()).isEqualTo(expectedSender);


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


[06/19] james-project git commit: JAMES-2214 Attachment checking should be extracted from SetMessagesCreationProcessor

Posted by ad...@apache.org.
JAMES-2214 Attachment checking should be extracted from SetMessagesCreationProcessor


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

Branch: refs/heads/master
Commit: b0f4d067ad6c1c0095a3898b71f59c976e215e11
Parents: d324caa
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 10:23:04 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 17:59:49 2017 +0700

----------------------------------------------------------------------
 .../james/jmap/methods/AttachmentChecker.java   |  73 +++++++++++++
 .../methods/SetMessagesCreationProcessor.java   |  47 ++-------
 .../jmap/methods/AttachmentCheckerTest.java     | 105 +++++++++++++++++++
 .../SetMessagesCreationProcessorTest.java       |  62 ++---------
 4 files changed, 190 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/b0f4d067/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/AttachmentChecker.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/AttachmentChecker.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/AttachmentChecker.java
new file mode 100644
index 0000000..77bbd62
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/AttachmentChecker.java
@@ -0,0 +1,73 @@
+/****************************************************************
+ * 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.methods;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.james.jmap.exceptions.AttachmentsNotFoundException;
+import org.apache.james.jmap.model.Attachment;
+import org.apache.james.jmap.model.BlobId;
+import org.apache.james.mailbox.AttachmentManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.AttachmentNotFoundException;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.AttachmentId;
+
+import com.github.fge.lambdas.Throwing;
+import com.github.fge.lambdas.predicates.ThrowingPredicate;
+import com.github.steveash.guavate.Guavate;
+
+public class AttachmentChecker {
+    private final AttachmentManager attachmentManager;
+
+    @Inject
+    public AttachmentChecker(AttachmentManager attachmentManager) {
+        this.attachmentManager = attachmentManager;
+    }
+
+    public void assertAttachmentsExist(ValueWithId.CreationMessageEntry entry, MailboxSession session) throws AttachmentsNotFoundException, MailboxException {
+        List<Attachment> attachments = entry.getValue().getAttachments();
+        List<BlobId> notFounds = listAttachmentsNotFound(attachments, session);
+        if (!notFounds.isEmpty()) {
+            throw new AttachmentsNotFoundException(notFounds);
+        }
+    }
+
+    private List<BlobId> listAttachmentsNotFound(List<Attachment> attachments, MailboxSession session) throws MailboxException {
+        ThrowingPredicate<Attachment> notExists = attachment -> {
+            try {
+                attachmentManager.getAttachment(getAttachmentId(attachment), session);
+                return false;
+            } catch (AttachmentNotFoundException e) {
+                return true;
+            }
+        };
+        return attachments.stream()
+            .filter(Throwing.predicate(notExists).sneakyThrow())
+            .map(Attachment::getBlobId)
+            .collect(Guavate.toImmutableList());
+    }
+
+    private AttachmentId getAttachmentId(Attachment attachment) {
+        return AttachmentId.from(attachment.getBlobId().getRawValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/b0f4d067/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 e2d13da..2f12ebd 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
@@ -32,8 +32,6 @@ import javax.mail.MessagingException;
 import org.apache.james.jmap.exceptions.AttachmentsNotFoundException;
 import org.apache.james.jmap.methods.ValueWithId.CreationMessageEntry;
 import org.apache.james.jmap.methods.ValueWithId.MessageWithId;
-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.Message;
 import org.apache.james.jmap.model.MessageFactory;
@@ -47,14 +45,11 @@ import org.apache.james.jmap.model.SetMessagesResponse;
 import org.apache.james.jmap.model.SetMessagesResponse.Builder;
 import org.apache.james.jmap.model.mailbox.Role;
 import org.apache.james.jmap.utils.SystemMailboxesProvider;
-import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
-import org.apache.james.mailbox.exception.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
-import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.metrics.api.MetricFactory;
 import org.apache.james.metrics.api.TimeMetric;
@@ -62,8 +57,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.github.fge.lambdas.Throwing;
-import com.github.fge.lambdas.predicates.ThrowingPredicate;
-import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
@@ -74,7 +67,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     private static final Logger LOG = LoggerFactory.getLogger(SetMailboxesCreationProcessor.class);
     private final MessageFactory messageFactory;
     private final SystemMailboxesProvider systemMailboxesProvider;
-    private final AttachmentManager attachmentManager;
+    private final AttachmentChecker attachmentChecker;
     private final MetricFactory metricFactory;
     private final MailboxManager mailboxManager;
     private final MailboxId.Factory mailboxIdFactory;
@@ -82,14 +75,15 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     private final MessageSender messageSender;
     
     @VisibleForTesting @Inject
-    SetMessagesCreationProcessor(MessageFactory messageFactory, SystemMailboxesProvider systemMailboxesProvider,
-                                 AttachmentManager attachmentManager,
+    SetMessagesCreationProcessor(MessageFactory messageFactory,
+                                 SystemMailboxesProvider systemMailboxesProvider,
+                                 AttachmentChecker attachmentChecker,
                                  MetricFactory metricFactory,
                                  MailboxManager mailboxManager,
                                  MailboxId.Factory mailboxIdFactory, MessageAppender messageAppender, MessageSender messageSender) {
         this.messageFactory = messageFactory;
         this.systemMailboxesProvider = systemMailboxesProvider;
-        this.attachmentManager = attachmentManager;
+        this.attachmentChecker = attachmentChecker;
         this.metricFactory = metricFactory;
         this.mailboxManager = mailboxManager;
         this.mailboxIdFactory = mailboxIdFactory;
@@ -186,36 +180,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         if (!message.isValid()) {
             throw new MailboxInvalidMessageCreationException();
         }
-        assertAttachmentsExist(entry, session);
-    }
-    
-    @VisibleForTesting void assertAttachmentsExist(CreationMessageEntry entry, MailboxSession session) throws AttachmentsNotFoundException, MailboxException {
-        List<Attachment> attachments = entry.getValue().getAttachments();
-        if (!attachments.isEmpty()) {
-            List<BlobId> notFounds = listAttachmentsNotFound(attachments, session);
-            if (!notFounds.isEmpty()) {
-                throw new AttachmentsNotFoundException(notFounds);
-            }
-        }
-    }
-
-    private List<BlobId> listAttachmentsNotFound(List<Attachment> attachments, MailboxSession session) throws MailboxException {
-        ThrowingPredicate<Attachment> notExists = attachment -> {
-            try {
-                attachmentManager.getAttachment(getAttachmentId(attachment), session);
-                return false;
-            } catch (AttachmentNotFoundException e) {
-                return true;
-            }
-        };
-        return attachments.stream()
-            .filter(Throwing.predicate(notExists).sneakyThrow())
-            .map(Attachment::getBlobId)
-            .collect(Guavate.toImmutableList());
-    }
-
-    private AttachmentId getAttachmentId(Attachment attachment) {
-        return AttachmentId.from(attachment.getBlobId().getRawValue());
+        attachmentChecker.assertAttachmentsExist(entry, session);
     }
 
     @VisibleForTesting void validateIsUserOwnerOfMailboxes(CreationMessageEntry entry, MailboxSession session) throws MailboxRightsException {

http://git-wip-us.apache.org/repos/asf/james-project/blob/b0f4d067/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
new file mode 100644
index 0000000..dca2a44
--- /dev/null
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/AttachmentCheckerTest.java
@@ -0,0 +1,105 @@
+/****************************************************************
+ * 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.methods;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.james.jmap.exceptions.AttachmentsNotFoundException;
+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.mailbox.AttachmentManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.AttachmentNotFoundException;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.mock.MockMailboxSession;
+import org.apache.james.mailbox.model.AttachmentId;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+public class AttachmentCheckerTest {
+
+    private final CreationMessageId creationMessageId = CreationMessageId.of("dlkja");
+    private final CreationMessage.Builder creationMessageBuilder = CreationMessage.builder()
+        .from(CreationMessage.DraftEmailer.builder().name("alice").email("alice@example.com").build())
+        .to(ImmutableList.of(CreationMessage.DraftEmailer.builder().name("bob").email("bob@example.com").build()))
+        .mailboxId("id")
+        .subject("Hey! ");
+
+    private AttachmentManager attachmentManager;
+    private MailboxSession session;
+
+    private AttachmentChecker sut;
+
+    @Before
+    public void setUp() {
+        session = new MockMailboxSession("Jonhy");
+        attachmentManager = mock(AttachmentManager.class);
+
+        sut = new AttachmentChecker(attachmentManager);
+    }
+
+    @Test
+    public void assertAttachmentsExistShouldThrowWhenUnknownBlobId() throws MailboxException {
+        BlobId unknownBlobId = BlobId.of("unknownBlobId");
+        AttachmentId unknownAttachmentId = AttachmentId.from(unknownBlobId.getRawValue());
+        when(attachmentManager.getAttachment(unknownAttachmentId, session)).thenThrow(new AttachmentNotFoundException(unknownBlobId.getRawValue()));
+
+        assertThatThrownBy(() -> sut.assertAttachmentsExist(
+            new ValueWithId.CreationMessageEntry(
+                creationMessageId,
+                creationMessageBuilder.attachments(
+                    Attachment.builder().size(12L).type("image/jpeg").blobId(unknownBlobId).build())
+                    .build()
+            ),
+            session))
+            .isInstanceOf(AttachmentsNotFoundException.class);
+    }
+
+    @Test
+    public void assertAttachmentsExistShouldThrowWhenUnknownBlobIds() throws MailboxException {
+        BlobId unknownBlobId1 = BlobId.of("unknownBlobId1");
+        BlobId unknownBlobId2 = BlobId.of("unknownBlobId2");
+        AttachmentId unknownAttachmentId1 = AttachmentId.from(unknownBlobId1.getRawValue());
+        AttachmentId unknownAttachmentId2 = AttachmentId.from(unknownBlobId2.getRawValue());
+
+        when(attachmentManager.getAttachment(unknownAttachmentId1, session)).thenThrow(new AttachmentNotFoundException(unknownBlobId1.getRawValue()));
+        when(attachmentManager.getAttachment(unknownAttachmentId2, session)).thenThrow(new AttachmentNotFoundException(unknownBlobId2.getRawValue()));
+
+        assertThatThrownBy(() -> sut.assertAttachmentsExist(
+            new ValueWithId.CreationMessageEntry(
+                creationMessageId,
+                creationMessageBuilder.attachments(
+                    Attachment.builder().size(12L).type("image/jpeg").blobId(unknownBlobId1).build(),
+                    Attachment.builder().size(23L).type("image/git").blobId(unknownBlobId2).build())
+                    .build()
+            ),
+            session))
+            .isInstanceOf(AttachmentsNotFoundException.class)
+            .matches(e -> ((AttachmentsNotFoundException)e).getAttachmentIds().containsAll(ImmutableSet.of(unknownBlobId1, unknownBlobId2)));
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/b0f4d067/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 25ece63..2857b1e 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
@@ -35,10 +35,7 @@ import java.util.stream.Stream;
 
 import javax.mail.Flags;
 
-import org.apache.james.jmap.exceptions.AttachmentsNotFoundException;
 import org.apache.james.jmap.methods.ValueWithId.CreationMessageEntry;
-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.CreationMessage.DraftEmailer;
 import org.apache.james.jmap.model.CreationMessageId;
@@ -60,14 +57,11 @@ import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MessageUid;
-import org.apache.james.mailbox.exception.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.mock.MockMailboxSession;
-import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.ComposedMessageId;
-import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxId.Factory;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageId;
@@ -84,7 +78,6 @@ 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 {
     
@@ -112,10 +105,8 @@ public class SetMessagesCreationProcessorTest {
 
     private MessageFactory messageFactory;
     private MailSpool mockedMailSpool;
-    private MailFactory mockedMailFactory;
     private SystemMailboxesProvider fakeSystemMailboxesProvider;
     private MockMailboxSession session;
-    private MIMEMessageConverter mimeMessageConverter;
     private AttachmentManager mockedAttachmentManager;
     private MailboxManager mockedMailboxManager;
     private Factory mockedMailboxIdFactory;
@@ -140,19 +131,19 @@ public class SetMessagesCreationProcessorTest {
         when(blobManager.toBlobId(any(MessageId.class))).thenReturn(org.apache.james.mailbox.model.BlobId.fromString("fake"));
         messageFactory = new MessageFactory(blobManager, messagePreview, messageContentExtractor, htmlTextExtractor);
         mockedMailSpool = mock(MailSpool.class);
-        mockedMailFactory = mock(MailFactory.class);
+        MailFactory mockedMailFactory = mock(MailFactory.class);
         mockedAttachmentManager = mock(AttachmentManager.class);
         mockedMailboxManager = mock(MailboxManager.class);
-        mockedMailboxIdFactory = mock(MailboxId.Factory.class);
+        mockedMailboxIdFactory = mock(Factory.class);
         
         fakeSystemMailboxesProvider = new TestSystemMailboxesProvider(() -> optionalOutbox, () -> optionalDrafts);
         session = new MockMailboxSession(USER);
-        mimeMessageConverter = new MIMEMessageConverter();
+        MIMEMessageConverter mimeMessageConverter = new MIMEMessageConverter();
         messageAppender = new MessageAppender(mockedAttachmentManager, mimeMessageConverter);
         messageSender = new MessageSender(mockedMailSpool, mockedMailFactory);
         sut = new SetMessagesCreationProcessor(messageFactory,
             fakeSystemMailboxesProvider,
-            mockedAttachmentManager,
+            new AttachmentChecker(mockedAttachmentManager),
             new NoopMetricFactory(),
             mockedMailboxManager,
             mockedMailboxIdFactory,
@@ -241,7 +232,7 @@ public class SetMessagesCreationProcessorTest {
     @Test
     public void processShouldReturnNonEmptyCreatedWhenRequestHasNonEmptyCreate() throws MailboxException {
         // Given
-        sut = new SetMessagesCreationProcessor(messageFactory, fakeSystemMailboxesProvider, mockedAttachmentManager, new NoopMetricFactory(), mockedMailboxManager, mockedMailboxIdFactory, messageAppender, messageSender);
+        sut = new SetMessagesCreationProcessor(messageFactory, fakeSystemMailboxesProvider, new AttachmentChecker(mockedAttachmentManager), new NoopMetricFactory(), mockedMailboxManager, mockedMailboxIdFactory, messageAppender, messageSender);
 
         // When
         SetMessagesResponse result = sut.process(createMessageInOutbox, session);
@@ -257,7 +248,7 @@ public class SetMessagesCreationProcessorTest {
         // Given
         TestSystemMailboxesProvider doNotProvideOutbox = new TestSystemMailboxesProvider(Optional::empty, () -> optionalDrafts);
         SetMessagesCreationProcessor sut = new SetMessagesCreationProcessor(messageFactory, doNotProvideOutbox,
-            mockedAttachmentManager, new NoopMetricFactory(), mockedMailboxManager, mockedMailboxIdFactory,
+            new AttachmentChecker(mockedAttachmentManager), new NoopMetricFactory(), mockedMailboxManager, mockedMailboxIdFactory,
             messageAppender,
             messageSender);
         // When
@@ -335,47 +326,6 @@ public class SetMessagesCreationProcessorTest {
         verify(mockedMailSpool, never()).send(any(Mail.class), any(MailMetadata.class));
     }
 
-
-    @Test
-    public void assertAttachmentsExistShouldThrowWhenUnknownBlobId() throws MailboxException {
-        BlobId unknownBlobId = BlobId.of("unknownBlobId");
-        AttachmentId unknownAttachmentId = AttachmentId.from(unknownBlobId.getRawValue());
-        when(mockedAttachmentManager.getAttachment(unknownAttachmentId, session)).thenThrow(new AttachmentNotFoundException(unknownBlobId.getRawValue()));
-        
-        assertThatThrownBy(() -> sut.assertAttachmentsExist(
-                new CreationMessageEntry(
-                        creationMessageId, 
-                        creationMessageBuilder.attachments(
-                                Attachment.builder().size(12l).type("image/jpeg").blobId(unknownBlobId).build())
-                            .build()
-                        ),
-                session))
-            .isInstanceOf(AttachmentsNotFoundException.class);
-    }
-    
-    @Test
-    public void assertAttachmentsExistShouldThrowWhenUnknownBlobIds() throws MailboxException {
-        BlobId unknownBlobId1 = BlobId.of("unknownBlobId1");
-        BlobId unknownBlobId2 = BlobId.of("unknownBlobId2");
-        AttachmentId unknownAttachmentId1 = AttachmentId.from(unknownBlobId1.getRawValue());
-        AttachmentId unknownAttachmentId2 = AttachmentId.from(unknownBlobId2.getRawValue());
-
-        when(mockedAttachmentManager.getAttachment(unknownAttachmentId1, session)).thenThrow(new AttachmentNotFoundException(unknownBlobId1.getRawValue()));
-        when(mockedAttachmentManager.getAttachment(unknownAttachmentId2, session)).thenThrow(new AttachmentNotFoundException(unknownBlobId2.getRawValue()));
-        
-        assertThatThrownBy(() -> sut.assertAttachmentsExist(
-                new CreationMessageEntry(
-                        creationMessageId, 
-                        creationMessageBuilder.attachments(
-                                Attachment.builder().size(12l).type("image/jpeg").blobId(unknownBlobId1).build(),
-                                Attachment.builder().size(23l).type("image/git").blobId(unknownBlobId2).build())
-                            .build()
-                        ),
-                session))
-            .isInstanceOf(AttachmentsNotFoundException.class)
-            .matches(e -> ((AttachmentsNotFoundException)e).getAttachmentIds().containsAll(ImmutableSet.of(unknownBlobId1, unknownBlobId2)));
-    }
-
     @Test
     public void validateIsUserOwnerOfMailboxesShouldThrowWhenMailboxIdDoesntExist() throws Exception {
         InMemoryId mailboxId = InMemoryId.of(6789);


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


[08/19] james-project git commit: JAMES-2214 Implement Draft saving via JMAP

Posted by ad...@apache.org.
JAMES-2214 Implement Draft saving via JMAP


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

Branch: refs/heads/master
Commit: fe0522ac5cc2eaa20619dcc8cef40075f9d39046
Parents: f85b5c6
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 11:46:22 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:04:09 2017 +0700

----------------------------------------------------------------------
 .../integration/SetMessagesMethodTest.java      | 540 ++++++++++++++++++-
 .../InvalidDraftKeywordsException.java          |  24 +
 .../james/jmap/methods/MessageAppender.java     |  18 +-
 .../methods/SetMessagesCreationProcessor.java   |  60 ++-
 .../SetMessagesCreationProcessorTest.java       |  27 +-
 5 files changed, 624 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/fe0522ac/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 3508e65..13e1da4 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
@@ -119,8 +119,8 @@ public abstract class SetMessagesMethodTest {
     private static final String SECOND_ARGUMENTS = "[1][1]";
     private static final String USERS_DOMAIN = "domain.tld";
     private static final String USERNAME = "username@" + USERS_DOMAIN;
-    private static final String PASSWORD = "password";
     private static final String BOB = "bob@" + USERS_DOMAIN;
+    private static final String PASSWORD = "password";
     private static final String BOB_PASSWORD = "bobPassword";
     private static final MailboxPath USER_MAILBOX = MailboxPath.forUser(USERNAME, "mailbox");
     private static final String NOT_UPDATED = ARGUMENTS + ".notUpdated";
@@ -194,6 +194,10 @@ public abstract class SetMessagesMethodTest {
         return getMailboxId(accessToken, Role.OUTBOX);
     }
 
+    private String getDraftId(AccessToken accessToken) {
+        return getMailboxId(accessToken, Role.DRAFTS);
+    }
+
     private String getMailboxId(AccessToken accessToken, Role role) {
         return getAllMailboxesIds(accessToken).stream()
             .filter(x -> x.get("role").equalsIgnoreCase(role.serialize()))
@@ -1291,6 +1295,7 @@ public abstract class SetMessagesMethodTest {
             .body(NAME, equalTo("messagesSet"))
             .body(ARGUMENTS + ".notCreated", hasKey(messageCreationId))
             .body(ARGUMENTS + ".notCreated[\""+messageCreationId+"\"].type", equalTo("error"))
+            .body(ARGUMENTS + ".notCreated[\""+messageCreationId+"\"].properties", contains("mailboxIds"))
             .body(ARGUMENTS + ".notCreated[\""+messageCreationId+"\"].description", endsWith("MailboxId invalid"));
     }
 
@@ -1361,8 +1366,529 @@ public abstract class SetMessagesMethodTest {
             .body(ARGUMENTS + ".created", aMapWithSize(1))
             .body(ARGUMENTS + ".created", hasKey(messageCreationId))
             .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].keywords.$Draft", equalTo(true))
-            .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].keywords.$Flagged", equalTo(true))
-            ;
+            .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].keywords.$Flagged", equalTo(true));
+    }
+
+    @Test
+    public void setMessagesShouldAllowDraftCreation() {
+        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\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 setMessagesShouldFailWhenSavingADraftInSeveralMailboxes() {
+        String messageCreationId = "creationId1337";
+        String fromAddress = USERNAME;
+        MailboxId mailboxId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\", \"" + mailboxId.serialize() + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 + "\"].properties", contains("mailboxIds"))
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", equalTo("Not yet implemented"));
+    }
+
+    @Test
+    public void setMessagesShouldBeCompatibleWithIsDraftProperty() {
+        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\"," +
+            "        \"isDraft\": true," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 setMessagesShouldRejectCreateInDraftAndOutboxForASingleMessage() {
+        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\": [\"" + getDraftId(accessToken) + "\", \"" +getOutboxId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 + "\"].properties", contains("mailboxIds"))
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", equalTo("Not yet implemented"));
+    }
+
+    @Test
+    public void setMessagesShouldStoreDraft() {
+        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\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        String receivedMessageId =
+            with()
+                .header("Authorization", accessToken.serialize())
+                .body(requestBody)
+                .post("/jmap")
+                .then()
+                .extract()
+                .path(ARGUMENTS + ".created[\""+messageCreationId+"\"].id");
+
+        String firstMessage = ARGUMENTS + ".list[0]";
+        given()
+            .header("Authorization", accessToken.serialize())
+            .body("[[\"getMessages\", {\"ids\": [\"" + receivedMessageId + "\"]}, \"#0\"]]")
+        .when()
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .body(NAME, equalTo("messages"))
+            .body(ARGUMENTS + ".list", hasSize(1))
+            .body(firstMessage + ".id", equalTo(receivedMessageId));
+    }
+
+    @Test
+    public void setMessagesShouldNotCheckFromWhenDraft() {
+        String messageCreationId = "creationId1337";
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"invalid@domain.com\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 setMessagesShouldNotCheckFromWhenInvalidEmailWhenDraft() {
+        String messageCreationId = "creationId1337";
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"invalid\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 setMessagesShouldAllowDraftCreationWithoutFrom() {
+        String messageCreationId = "creationId1337";
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 setMessagesShouldAllowDraftCreationWithoutRecipients() {
+        String messageCreationId = "creationId1337";
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"invalid@domain.com\"}," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 setMessagesShouldRequireDraftFlagWhenSavingDraft() {
+        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\": {\"$Flagged\": true}," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 + "\"].properties", contains("keywords"))
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", equalTo("A draft message should be flagged as Draft"));
+    }
+
+    @Test
+    public void setMessagesShouldCheckAttachmentsWhenDraft() {
+        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}," +
+            "        \"attachments\": [" +
+            "                {\"blobId\" : \"wrong\", \"type\" : \"image/jpeg\", \"size\" : 1337}" +
+            "             ]," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 + "\"].properties", contains("attachments"))
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", equalTo("Attachment not found"));
+    }
+
+    @Test
+    public void setMessagesShouldAcceptAttachmentsWhenDraft() throws Exception {
+        String messageCreationId = "creationId1337";
+        String fromAddress = USERNAME;
+        Attachment attachment = Attachment.builder()
+            .bytes("attachment".getBytes(Charsets.UTF_8))
+            .type("application/octet-stream")
+            .build();
+        uploadAttachment(attachment);
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"attachments\": [" +
+            "                {\"blobId\" : \"" + attachment.getAttachmentId().getId() + "\", " +
+            "                 \"type\" : \"" + attachment.getType() + "\"," +
+            "                 \"size\" : " + attachment.getSize() + "}" +
+            "             ]," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#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 setMessagesShouldNotAllowDraftCreationInSomeoneElseMailbox() throws Exception {
+        String messageCreationId = "creationId1337";
+        Attachment attachment = Attachment.builder()
+            .bytes("attachment".getBytes(Charsets.UTF_8))
+            .type("application/octet-stream")
+            .build();
+        uploadAttachment(attachment);
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        given()
+            .header("Authorization", bobAccessToken.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("error"))
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", endsWith("can not be found"));
+    }
+
+    @Test
+    public void setMessagesShouldNotAllowDraftCreationInADelegatedMailbox() throws Exception {
+        String messageCreationId = "creationId1337";
+        Attachment attachment = Attachment.builder()
+            .bytes("attachment".getBytes(Charsets.UTF_8))
+            .type("application/octet-stream")
+            .build();
+        uploadAttachment(attachment);
+
+        jmapServer.getProbe(ACLProbeImpl.class)
+            .addRights(
+                MailboxPath.forUser(USERNAME, DefaultMailboxes.DRAFTS),
+                BOB,
+                MailboxACL.FULL_RIGHTS);
+
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        given()
+            .header("Authorization", bobAccessToken.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("error"))
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].properties", contains("mailboxIds"))
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", endsWith("MailboxId invalid"));
     }
 
     @Test
@@ -1814,10 +2340,9 @@ public abstract class SetMessagesMethodTest {
     public void setMessagesShouldStripBccFromDeliveredEmail() throws Exception {
         // Recipient
         String recipientAddress = "recipient" + "@" + USERS_DOMAIN;
-        String bccRecipient = "bob@" + USERS_DOMAIN;
+        String bccRecipient = BOB;
         String password = "password";
         dataProbe.addUser(recipientAddress, password);
-        dataProbe.addUser(bccRecipient, password);
         mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, recipientAddress, DefaultMailboxes.INBOX);
         await();
         AccessToken recipientToken = HttpJmapAuthentication.authenticateJamesUser(baseUri(), recipientAddress, password);
@@ -1933,7 +2458,6 @@ public abstract class SetMessagesMethodTest {
         String bccAddress = BOB;
         mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, bccAddress, DefaultMailboxes.INBOX);
         await();
-        AccessToken bccToken = HttpJmapAuthentication.authenticateJamesUser(baseUri(), BOB, BOB_PASSWORD);
 
         String messageCreationId = "creationId1337";
         String fromAddress = USERNAME;
@@ -1964,9 +2488,9 @@ public abstract class SetMessagesMethodTest {
             .post("/jmap");
 
         // Then
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInRecipientsMailboxes(bccToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInRecipientsMailboxes(bobAccessToken));
         with()
-            .header("Authorization", bccToken.serialize())
+            .header("Authorization", bobAccessToken.serialize())
             .body("[[\"getMessageList\", {\"fetchMessages\": true, \"fetchMessageProperties\": [\"bcc\"] }, \"#0\"]]")
         .when()
             .post("/jmap")

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe0522ac/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/InvalidDraftKeywordsException.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/InvalidDraftKeywordsException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/InvalidDraftKeywordsException.java
new file mode 100644
index 0000000..08dd9b6
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/InvalidDraftKeywordsException.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 InvalidDraftKeywordsException extends IllegalArgumentException {
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe0522ac/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 4b1fad6..4d09810 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
@@ -25,10 +25,12 @@ import java.util.Optional;
 import javax.inject.Inject;
 import javax.mail.util.SharedByteArrayInputStream;
 
+import org.apache.james.jmap.methods.ValueWithId.CreationMessageEntry;
 import org.apache.james.jmap.model.Attachment;
 import org.apache.james.jmap.model.Keywords;
 import org.apache.james.jmap.model.MessageFactory;
 import org.apache.james.mailbox.AttachmentManager;
+import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.exception.AttachmentNotFoundException;
@@ -36,6 +38,7 @@ import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.Cid;
 import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.util.OptionalUtils;
 import org.slf4j.Logger;
@@ -49,16 +52,18 @@ import com.google.common.collect.ImmutableList;
 public class MessageAppender {
     private static final Logger LOGGER = LoggerFactory.getLogger(MessageAppender.class);
 
+    private final MailboxManager mailboxManager;
     private final AttachmentManager attachmentManager;
     private final MIMEMessageConverter mimeMessageConverter;
 
     @Inject
-    public MessageAppender(AttachmentManager attachmentManager, MIMEMessageConverter mimeMessageConverter) {
+    public MessageAppender(MailboxManager mailboxManager, AttachmentManager attachmentManager, MIMEMessageConverter mimeMessageConverter) {
+        this.mailboxManager = mailboxManager;
         this.attachmentManager = attachmentManager;
         this.mimeMessageConverter = mimeMessageConverter;
     }
 
-    public MessageFactory.MetaDataWithContent createMessageInMailbox(ValueWithId.MessageWithId.CreationMessageEntry createdEntry,
+    public MessageFactory.MetaDataWithContent appendMessageInMailbox(CreationMessageEntry createdEntry,
                                                                      MessageManager mailbox,
                                                                      MailboxSession session) throws MailboxException {
         ImmutableList<MessageAttachment> messageAttachments = getMessageAttachments(session, createdEntry.getValue().getAttachments());
@@ -85,6 +90,14 @@ public class MessageAppender {
             .build();
     }
 
+    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()
@@ -102,7 +115,6 @@ public class MessageAppender {
                 .isInline(attachment.isIsInline())
                 .build());
         } catch (AttachmentNotFoundException e) {
-            // should not happen (checked before)
             LOGGER.error(String.format("Attachment %s not found", attachment.getBlobId()), e);
             return Optional.empty();
         } catch (IllegalStateException e) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe0522ac/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 870235c..a91a65c 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
@@ -30,9 +30,11 @@ import javax.inject.Inject;
 import javax.mail.MessagingException;
 
 import org.apache.james.jmap.exceptions.AttachmentsNotFoundException;
+import org.apache.james.jmap.exceptions.InvalidDraftKeywordsException;
 import org.apache.james.jmap.methods.ValueWithId.CreationMessageEntry;
 import org.apache.james.jmap.methods.ValueWithId.MessageWithId;
 import org.apache.james.jmap.model.CreationMessage;
+import org.apache.james.jmap.model.Keyword;
 import org.apache.james.jmap.model.Message;
 import org.apache.james.jmap.model.MessageFactory;
 import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent;
@@ -107,11 +109,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     private void handleCreate(CreationMessageEntry create, Builder responseBuilder, MailboxSession mailboxSession) {
         try {
             validateIsUserOwnerOfMailboxes(create, mailboxSession);
-            validateImplementedFeature(create, mailboxSession);
-            validateArguments(create, mailboxSession);
-            MessageWithId created = handleOutboxMessages(create, mailboxSession);
-            responseBuilder.created(created.getCreationId(), created.getValue());
-
+            performCreate(create, responseBuilder, mailboxSession);
         } catch (MailboxSendingNotAllowedException e) {
             responseBuilder.notCreated(create.getCreationId(), 
                     SetError.builder()
@@ -121,6 +119,14 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
                                 Joiner.on(", ").join(e.getAllowedFroms()))
                         .build());
 
+        } catch (InvalidDraftKeywordsException e) {
+            responseBuilder.notCreated(create.getCreationId(),
+                SetError.builder()
+                    .type("invalidProperties")
+                    .properties(MessageProperty.keywords)
+                    .description("A draft message should be flagged as Draft")
+                    .build());
+
         } catch (AttachmentsNotFoundException e) {
             responseBuilder.notCreated(create.getCreationId(), 
                     SetMessagesError.builder()
@@ -154,6 +160,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
             responseBuilder.notCreated(create.getCreationId(), 
                     SetError.builder()
                         .type("error")
+                        .properties(MessageProperty.mailboxIds)
                         .description("MailboxId invalid")
                         .build());
 
@@ -167,15 +174,39 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         }
     }
     
-    private void validateImplementedFeature(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MailboxNotImplementedException {
+    private void performCreate(CreationMessageEntry entry, Builder responseBuilder, MailboxSession session) throws MailboxException, MailboxNotImplementedException, MessagingException, AttachmentsNotFoundException {
         if (isAppendToMailboxWithRole(Role.DRAFTS, entry.getValue(), session)) {
-            throw new MailboxNotImplementedException("Drafts saving is not implemented");
+            saveDraft(entry, responseBuilder, session);
+        } else if (isAppendToMailboxWithRole(Role.OUTBOX, entry.getValue(), session)) {
+            sendMailViaOutbox(entry, responseBuilder, session);
+        } else {
+            throw new MailboxNotImplementedException("The only implemented feature is sending via outbox and draft saving");
         }
-        if (!isAppendToMailboxWithRole(Role.OUTBOX, entry.getValue(), session)) {
-            throw new MailboxNotImplementedException("The only implemented feature is sending via outbox");
+    }
+
+    private void sendMailViaOutbox(CreationMessageEntry entry, Builder responseBuilder, MailboxSession session) throws AttachmentsNotFoundException, MailboxException, MessagingException {
+        validateArguments(entry, session);
+        MessageWithId created = handleOutboxMessages(entry, session);
+        responseBuilder.created(created.getCreationId(), created.getValue());
+    }
+
+    private void saveDraft(CreationMessageEntry entry, Builder responseBuilder, MailboxSession session) throws AttachmentsNotFoundException, MailboxException, MessagingException {
+        attachmentChecker.assertAttachmentsExist(entry, session);
+        assertDraftKeywords(entry);
+        MessageWithId created = handleDraftMessages(entry, session);
+        responseBuilder.created(created.getCreationId(), created.getValue());
+    }
+
+    private void assertDraftKeywords(CreationMessageEntry entry) {
+        Boolean isDraft = entry.getValue()
+            .getKeywords()
+            .map(keywords -> keywords.contains(Keyword.DRAFT))
+            .orElse(false);
+        if (!isDraft) {
+            throw new InvalidDraftKeywordsException();
         }
     }
-    
+
     private void validateArguments(CreationMessageEntry entry, MailboxSession session) throws MailboxInvalidMessageCreationException, AttachmentsNotFoundException, MailboxException {
         CreationMessage message = entry.getValue();
         if (!message.isValid()) {
@@ -201,11 +232,18 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private MessageWithId handleOutboxMessages(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MessagingException {
         MessageManager outbox = getMailboxWithRole(session, Role.OUTBOX).orElseThrow(() -> new MailboxNotFoundException(Role.OUTBOX.serialize()));
-        MetaDataWithContent newMessage = messageAppender.createMessageInMailbox(entry, outbox, session);
+        MetaDataWithContent newMessage = messageAppender.appendMessageInMailbox(entry, outbox, session);
         Message jmapMessage = messageFactory.fromMetaDataWithContent(newMessage);
         messageSender.sendMessage(jmapMessage, newMessage, session);
         return new ValueWithId.MessageWithId(entry.getCreationId(), jmapMessage);
     }
+
+    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);
+        Message jmapMessage = messageFactory.fromMetaDataWithContent(newMessage);
+        return new ValueWithId.MessageWithId(entry.getCreationId(), jmapMessage);
+    }
     
     private boolean isAppendToMailboxWithRole(Role role, CreationMessage entry, MailboxSession mailboxSession) throws MailboxException {
         return getMailboxWithRole(mailboxSession, role)

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe0522ac/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 1ef68ea..a0df1b4 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
@@ -41,8 +41,6 @@ import org.apache.james.jmap.model.CreationMessage.DraftEmailer;
 import org.apache.james.jmap.model.CreationMessageId;
 import org.apache.james.jmap.model.MessageFactory;
 import org.apache.james.jmap.model.MessagePreviewGenerator;
-import org.apache.james.jmap.model.MessageProperties.MessageProperty;
-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.mailbox.Role;
@@ -140,7 +138,7 @@ public class SetMessagesCreationProcessorTest {
         fakeSystemMailboxesProvider = new TestSystemMailboxesProvider(() -> optionalOutbox, () -> optionalDrafts);
         session = new MockMailboxSession(USER);
         MIMEMessageConverter mimeMessageConverter = new MIMEMessageConverter();
-        messageAppender = new MessageAppender(mockedAttachmentManager, mimeMessageConverter);
+        messageAppender = new MessageAppender(mockedMailboxManager, mockedAttachmentManager, mimeMessageConverter);
         messageSender = new MessageSender(mockedMailSpool, mockedMailFactory);
         sut = new SetMessagesCreationProcessor(messageFactory,
             fakeSystemMailboxesProvider,
@@ -297,25 +295,6 @@ public class SetMessagesCreationProcessorTest {
     }
 
     @Test
-    public void processShouldReturnNotImplementedErrorWhenSavingToDrafts() {
-        CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
-        SetMessagesRequest createMessageInDrafts = SetMessagesRequest.builder()
-                .create(
-                        creationMessageId, creationMessageBuilder.mailboxId(DRAFTS_ID.serialize()).build())
-                .build();
-
-        // When
-        SetMessagesResponse actual = sut.process(createMessageInDrafts, session);
-
-        // Then
-        assertThat(actual.getNotCreated()).hasSize(1).containsEntry(creationMessageId, SetError.builder()
-                .type("invalidProperties")
-                .properties(MessageProperty.mailboxIds)
-                .description("Not yet implemented")
-                .build());
-    }
-
-    @Test
     public void processShouldNotSendWhenSavingToDrafts() throws Exception {
         // When
         CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
@@ -323,7 +302,9 @@ public class SetMessagesCreationProcessorTest {
                 .create(
                         creationMessageId, creationMessageBuilder.mailboxId(DRAFTS_ID.serialize()).build())
                 .build();
-        when(mockedMailboxManager.getMailbox(any(MailboxId.class), any())).thenReturn(drafts);
+        when(mockedMailboxManager.getMailbox(any(MailboxId.class), any()))
+            .thenReturn(drafts);
+        
         sut.process(createMessageInDrafts, session);
 
         // Then


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


[07/19] james-project git commit: JAMES-2214 Rename ambiguous and misleading MailboxRightsException

Posted by ad...@apache.org.
JAMES-2214 Rename ambiguous and misleading MailboxRightsException

MailboxRightsException leads to think it concerns mailbox rights, but was raised when having rights on a delegated 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/1e8d057c
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/1e8d057c
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/1e8d057c

Branch: refs/heads/master
Commit: 1e8d057c9bcd3906d5e018baaef83b7681b9ec38
Parents: fe0522a
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 13:00:21 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:04:09 2017 +0700

----------------------------------------------------------------------
 .../exceptions/MailboxNotOwnedException.java    | 29 ++++++++++++++++++++
 .../jmap/methods/MailboxRightsException.java    | 29 --------------------
 .../methods/SetMessagesCreationProcessor.java   |  7 +++--
 .../SetMessagesCreationProcessorTest.java       |  3 +-
 4 files changed, 35 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/1e8d057c/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxNotOwnedException.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxNotOwnedException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxNotOwnedException.java
new file mode 100644
index 0000000..714305a
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxNotOwnedException.java
@@ -0,0 +1,29 @@
+/****************************************************************
+ * 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;
+
+import org.apache.james.mailbox.exception.MailboxException;
+
+public class MailboxNotOwnedException extends MailboxException {
+
+    public MailboxNotOwnedException() {
+        super();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/1e8d057c/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxRightsException.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxRightsException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxRightsException.java
deleted file mode 100644
index f47e7d0..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxRightsException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/****************************************************************
- * 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.methods;
-
-import org.apache.james.mailbox.exception.MailboxException;
-
-public class MailboxRightsException extends MailboxException {
-
-    public MailboxRightsException() {
-        super();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/1e8d057c/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 a91a65c..71e3a11 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
@@ -31,6 +31,7 @@ import javax.mail.MessagingException;
 
 import org.apache.james.jmap.exceptions.AttachmentsNotFoundException;
 import org.apache.james.jmap.exceptions.InvalidDraftKeywordsException;
+import org.apache.james.jmap.exceptions.MailboxNotOwnedException;
 import org.apache.james.jmap.methods.ValueWithId.CreationMessageEntry;
 import org.apache.james.jmap.methods.ValueWithId.MessageWithId;
 import org.apache.james.jmap.model.CreationMessage;
@@ -155,7 +156,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
                         .description(e.getMessage())
                         .build());
 
-        } catch (MailboxRightsException e) {
+        } catch (MailboxNotOwnedException e) {
             LOG.error("Appending message in an unknown mailbox", e);
             responseBuilder.notCreated(create.getCreationId(), 
                     SetError.builder()
@@ -215,9 +216,9 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         attachmentChecker.assertAttachmentsExist(entry, session);
     }
 
-    @VisibleForTesting void validateIsUserOwnerOfMailboxes(CreationMessageEntry entry, MailboxSession session) throws MailboxRightsException {
+    @VisibleForTesting void validateIsUserOwnerOfMailboxes(CreationMessageEntry entry, MailboxSession session) throws MailboxNotOwnedException {
         if (containsMailboxNotOwn(entry.getValue().getMailboxIds(), session)) {
-            throw new MailboxRightsException();
+            throw new MailboxNotOwnedException();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/1e8d057c/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 a0df1b4..8a55816 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
@@ -35,6 +35,7 @@ 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;
@@ -357,7 +358,7 @@ public class SetMessagesCreationProcessorTest {
         CreationMessageEntry entry = new CreationMessageEntry(creationMessageId, creationMessageBuilder.mailboxId(mailboxId.serialize()).build());
 
         assertThatThrownBy(() -> sut.validateIsUserOwnerOfMailboxes(entry, session))
-            .isInstanceOf(MailboxRightsException.class);
+            .isInstanceOf(MailboxNotOwnedException.class);
     }
 
     @Test


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


[12/19] james-project git commit: JAMES-2214 Only one From address is supported: the user name

Posted by ad...@apache.org.
JAMES-2214 Only one From address is supported: the user name


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

Branch: refs/heads/master
Commit: 46e520e621b6c0ae4a9ec8733cf2eb34c066a71e
Parents: 90f3fb7
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 16:23:17 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:45 2017 +0700

----------------------------------------------------------------------
 .../methods/integration/SetMessagesMethodTest.java    |  2 +-
 .../methods/MailboxSendingNotAllowedException.java    | 12 +++++-------
 .../org/apache/james/jmap/methods/MessageSender.java  | 14 +++++---------
 .../jmap/methods/SetMessagesCreationProcessor.java    |  5 ++---
 4 files changed, 13 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/46e520e6/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 97fbf15..ad99100 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
@@ -2290,7 +2290,7 @@ public abstract class SetMessagesMethodTest {
             .body(ARGUMENTS + ".notCreated[\""+messageCreationId+"\"].type", equalTo("invalidProperties"))
             .body(ARGUMENTS + ".notCreated[\""+messageCreationId+"\"].properties", hasSize(1))
             .body(ARGUMENTS + ".notCreated[\""+messageCreationId+"\"].properties", contains("from"))
-            .body(ARGUMENTS + ".notCreated[\""+messageCreationId+"\"].description", endsWith("Invalid 'from' field. Must be one of username@domain.tld"))
+            .body(ARGUMENTS + ".notCreated[\""+messageCreationId+"\"].description", endsWith("Invalid 'from' field. Must be username@domain.tld"))
             .body(ARGUMENTS + ".created", aMapWithSize(0));
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/46e520e6/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxSendingNotAllowedException.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxSendingNotAllowedException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxSendingNotAllowedException.java
index 49d9141..83d36c8 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxSendingNotAllowedException.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MailboxSendingNotAllowedException.java
@@ -19,20 +19,18 @@
 
 package org.apache.james.jmap.methods;
 
-import java.util.Collection;
-
 import org.apache.james.mailbox.exception.MailboxException;
 
 public class MailboxSendingNotAllowedException extends MailboxException {
 
-    private Collection<String> allowedFroms;
+    private String allowedFrom;
 
-    public MailboxSendingNotAllowedException(Collection<String> allowedFroms) {
+    public MailboxSendingNotAllowedException(String allowedFrom) {
         super();
-        this.allowedFroms = allowedFroms;
+        this.allowedFrom = allowedFrom;
     }
     
-    public Collection<String> getAllowedFroms() {
-        return allowedFroms;
+    public String getAllowedFrom() {
+        return allowedFrom;
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/46e520e6/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
index 98e41d2..ab360ea 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
@@ -20,12 +20,10 @@
 package org.apache.james.jmap.methods;
 
 import java.io.IOException;
-import java.util.List;
 
 import javax.inject.Inject;
 import javax.mail.MessagingException;
 
-import org.apache.james.jmap.model.CreationMessageId;
 import org.apache.james.jmap.model.Message;
 import org.apache.james.jmap.model.MessageFactory;
 import org.apache.james.jmap.send.MailFactory;
@@ -36,8 +34,6 @@ import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.mailet.Mail;
 
-import com.google.common.collect.ImmutableList;
-
 public class MessageSender {
     private final MailSpool mailSpool;
     private final MailFactory mailFactory;
@@ -70,16 +66,16 @@ public class MessageSender {
     }
 
     private void validateUserIsInSenders(Message message, MailboxSession session) throws MailboxSendingNotAllowedException {
-        List<String> allowedSenders = ImmutableList.of(session.getUser().getUserName());
-        if (!isAllowedFromAddress(message, allowedSenders)) {
-            throw new MailboxSendingNotAllowedException(allowedSenders);
+        String allowedSender = session.getUser().getUserName();
+        if (!isAllowedFromAddress(message, allowedSender)) {
+            throw new MailboxSendingNotAllowedException(allowedSender);
         }
     }
 
-    private boolean isAllowedFromAddress(Message message, List<String> allowedFromMailAddresses) {
+    private boolean isAllowedFromAddress(Message message, String allowedFromMailAddress) {
         return message.getFrom()
             .map(draftEmailer -> draftEmailer.getEmail()
-                .map(allowedFromMailAddresses::contains)
+                .map(allowedFromMailAddress::equals)
                 .orElse(false))
             .orElse(false);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/46e520e6/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 ac12072..19dc981 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
@@ -63,7 +63,6 @@ import org.slf4j.LoggerFactory;
 import com.github.fge.lambdas.Throwing;
 import com.github.fge.lambdas.functions.FunctionChainer;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
 
 
@@ -117,8 +116,8 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
                     SetError.builder()
                         .type("invalidProperties")
                         .properties(MessageProperty.from)
-                        .description("Invalid 'from' field. Must be one of " + 
-                                Joiner.on(", ").join(e.getAllowedFroms()))
+                        .description("Invalid 'from' field. Must be " +
+                                e.getAllowedFrom())
                         .build());
 
         } catch (InvalidDraftKeywordsException e) {


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


[15/19] james-project git commit: JAMES-2214 MailFactory should not throw IOException

Posted by ad...@apache.org.
JAMES-2214 MailFactory should not throw IOException


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

Branch: refs/heads/master
Commit: 9f1d7672ca92be42ffba4cdaac37a3149c099e51
Parents: a04c071
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 17:17:22 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:45 2017 +0700

----------------------------------------------------------------------
 .../org/apache/james/jmap/methods/MessageSender.java    | 12 +-----------
 .../java/org/apache/james/jmap/send/MailFactory.java    |  4 +---
 2 files changed, 2 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/9f1d7672/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
index 8d86355..3ce4086 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
@@ -19,8 +19,6 @@
 
 package org.apache.james.jmap.methods;
 
-import java.io.IOException;
-
 import javax.inject.Inject;
 import javax.mail.MessagingException;
 
@@ -48,7 +46,7 @@ public class MessageSender {
                             Envelope envelope,
                             MailboxSession session) throws MailboxException, MessagingException {
         assertUserIsInSenders(envelope, session);
-        Mail mail = buildMessage(message, envelope);
+        Mail mail = mailFactory.build(message, envelope);
         try {
             MailMetadata metadata = new MailMetadata(message.getMessageId(), session.getUser().getUserName());
             mailSpool.send(mail, metadata);
@@ -57,14 +55,6 @@ public class MessageSender {
         }
     }
 
-    private Mail buildMessage(MessageFactory.MetaDataWithContent message, Envelope envelope) throws MessagingException {
-        try {
-            return mailFactory.build(message, envelope);
-        } catch (IOException e) {
-            throw new MessagingException("error building message to send", e);
-        }
-    }
-
     private void assertUserIsInSenders(Envelope envelope, MailboxSession session) throws MailboxSendingNotAllowedException {
         String allowedSender = session.getUser().getUserName();
         if (!session.getUser().isSameUser(envelope.getFrom().asString())) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/9f1d7672/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
index 7db6a9b..405bab1 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailFactory.java
@@ -19,8 +19,6 @@
 
 package org.apache.james.jmap.send;
 
-import java.io.IOException;
-
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
@@ -38,7 +36,7 @@ public class MailFactory {
     @VisibleForTesting MailFactory() {
     }
 
-    public Mail build(MetaDataWithContent message, Envelope envelope) throws MessagingException, IOException {
+    public Mail build(MetaDataWithContent message, Envelope envelope) throws MessagingException {
         ImmutableSet<MailAddress> recipients = Sets.union(
             Sets.union(envelope.getTo(), envelope.getCc()),
                 envelope.getBcc()).immutableCopy();


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


[02/19] james-project git commit: JAMES-2214 Introduce helper class for saving and sending emails with JMAP

Posted by ad...@apache.org.
JAMES-2214 Introduce helper class for saving and sending emails with JMAP


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

Branch: refs/heads/master
Commit: 4dbe064d2e516804f2a058313f83fd7ce078f838
Parents: b539779
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 13:22:44 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 17:58:15 2017 +0700

----------------------------------------------------------------------
 .../james/jmap/methods/MessageAppender.java     | 113 ++++++++++++++++++
 .../james/jmap/methods/MessageSender.java       |  70 +++++++++++
 .../methods/SetMessagesCreationProcessor.java   | 117 ++-----------------
 .../SetMessagesCreationProcessorTest.java       |  20 +++-
 4 files changed, 211 insertions(+), 109 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/4dbe064d/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
new file mode 100644
index 0000000..4b1fad6
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageAppender.java
@@ -0,0 +1,113 @@
+/****************************************************************
+ * 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.methods;
+
+import java.util.Date;
+import java.util.Optional;
+
+import javax.inject.Inject;
+import javax.mail.util.SharedByteArrayInputStream;
+
+import org.apache.james.jmap.model.Attachment;
+import org.apache.james.jmap.model.Keywords;
+import org.apache.james.jmap.model.MessageFactory;
+import org.apache.james.mailbox.AttachmentManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.exception.AttachmentNotFoundException;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.AttachmentId;
+import org.apache.james.mailbox.model.Cid;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.MessageAttachment;
+import org.apache.james.util.OptionalUtils;
+import org.slf4j.Logger;
+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.collect.ImmutableList;
+
+public class MessageAppender {
+    private static final Logger LOGGER = LoggerFactory.getLogger(MessageAppender.class);
+
+    private final AttachmentManager attachmentManager;
+    private final MIMEMessageConverter mimeMessageConverter;
+
+    @Inject
+    public MessageAppender(AttachmentManager attachmentManager, MIMEMessageConverter mimeMessageConverter) {
+        this.attachmentManager = attachmentManager;
+        this.mimeMessageConverter = mimeMessageConverter;
+    }
+
+    public MessageFactory.MetaDataWithContent createMessageInMailbox(ValueWithId.MessageWithId.CreationMessageEntry createdEntry,
+                                                                     MessageManager mailbox,
+                                                                     MailboxSession session) throws MailboxException {
+        ImmutableList<MessageAttachment> messageAttachments = getMessageAttachments(session, createdEntry.getValue().getAttachments());
+        byte[] messageContent = mimeMessageConverter.convert(createdEntry, messageAttachments);
+        SharedByteArrayInputStream content = new SharedByteArrayInputStream(messageContent);
+        Date internalDate = Date.from(createdEntry.getValue().getDate().toInstant());
+
+        Keywords keywords = createdEntry.getValue()
+            .getKeywords()
+            .orElse(Keywords.DEFAULT_VALUE);
+        boolean notRecent = false;
+
+        ComposedMessageId message = mailbox.appendMessage(content, internalDate, session, notRecent, keywords.asFlags());
+
+        return MessageFactory.MetaDataWithContent.builder()
+            .uid(message.getUid())
+            .keywords(keywords)
+            .internalDate(internalDate.toInstant())
+            .sharedContent(content)
+            .size(messageContent.length)
+            .attachments(messageAttachments)
+            .mailboxId(mailbox.getId())
+            .messageId(message.getMessageId())
+            .build();
+    }
+
+    private ImmutableList<MessageAttachment> getMessageAttachments(MailboxSession session, ImmutableList<Attachment> attachments) throws MailboxException {
+        ThrowingFunction<Attachment, Optional<MessageAttachment>> toMessageAttachment = att -> messageAttachment(session, att);
+        return attachments.stream()
+            .map(Throwing.function(toMessageAttachment).sneakyThrow())
+            .flatMap(OptionalUtils::toStream)
+            .collect(Guavate.toImmutableList());
+    }
+
+    private Optional<MessageAttachment> messageAttachment(MailboxSession session, Attachment attachment) throws MailboxException {
+        try {
+            return Optional.of(MessageAttachment.builder()
+                .attachment(attachmentManager.getAttachment(AttachmentId.from(attachment.getBlobId().getRawValue()), session))
+                .name(attachment.getName().orElse(null))
+                .cid(attachment.getCid().map(Cid::from).orElse(null))
+                .isInline(attachment.isIsInline())
+                .build());
+        } catch (AttachmentNotFoundException e) {
+            // should not happen (checked before)
+            LOGGER.error(String.format("Attachment %s not found", attachment.getBlobId()), e);
+            return Optional.empty();
+        } catch (IllegalStateException e) {
+            LOGGER.error(String.format("Attachment %s is not well-formed", attachment.getBlobId()), e);
+            return Optional.empty();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4dbe064d/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
new file mode 100644
index 0000000..dd94618
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
@@ -0,0 +1,70 @@
+/****************************************************************
+ * 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.methods;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.mail.MessagingException;
+
+import org.apache.james.jmap.model.CreationMessageId;
+import org.apache.james.jmap.model.Message;
+import org.apache.james.jmap.model.MessageFactory;
+import org.apache.james.jmap.send.MailFactory;
+import org.apache.james.jmap.send.MailMetadata;
+import org.apache.james.jmap.send.MailSpool;
+import org.apache.james.lifecycle.api.LifecycleUtil;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.mailet.Mail;
+
+import com.google.common.collect.ImmutableList;
+
+public class MessageSender {
+    private final MailSpool mailSpool;
+    private final MailFactory mailFactory;
+
+    @Inject
+    public MessageSender(MailSpool mailSpool, MailFactory mailFactory) {
+        this.mailSpool = mailSpool;
+        this.mailFactory = mailFactory;
+    }
+
+    public void sendMessage(Message jmapMessage,
+                            MessageFactory.MetaDataWithContent message,
+                            MailboxSession session) throws MailboxException, MessagingException {
+        Mail mail = buildMessage(message, jmapMessage);
+        try {
+            MailMetadata metadata = new MailMetadata(jmapMessage.getId(), session.getUser().getUserName());
+            mailSpool.send(mail, metadata);
+        } finally {
+            LifecycleUtil.dispose(mail);
+        }
+    }
+
+    private Mail buildMessage(MessageFactory.MetaDataWithContent message, Message jmapMessage) throws MessagingException {
+        try {
+            return mailFactory.build(message, jmapMessage);
+        } catch (IOException e) {
+            throw new MessagingException("error building message to send", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4dbe064d/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 8c482e3..8fe1161 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
@@ -21,8 +21,6 @@ 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;
@@ -30,7 +28,6 @@ import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.mail.MessagingException;
-import javax.mail.util.SharedByteArrayInputStream;
 
 import org.apache.james.jmap.exceptions.AttachmentsNotFoundException;
 import org.apache.james.jmap.methods.ValueWithId.CreationMessageEntry;
@@ -38,8 +35,6 @@ import org.apache.james.jmap.methods.ValueWithId.MessageWithId;
 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;
@@ -51,11 +46,7 @@ import org.apache.james.jmap.model.SetMessagesRequest;
 import org.apache.james.jmap.model.SetMessagesResponse;
 import org.apache.james.jmap.model.SetMessagesResponse.Builder;
 import org.apache.james.jmap.model.mailbox.Role;
-import org.apache.james.jmap.send.MailFactory;
-import org.apache.james.jmap.send.MailMetadata;
-import org.apache.james.jmap.send.MailSpool;
 import org.apache.james.jmap.utils.SystemMailboxesProvider;
-import org.apache.james.lifecycle.api.LifecycleUtil;
 import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
@@ -64,19 +55,13 @@ import org.apache.james.mailbox.exception.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.AttachmentId;
-import org.apache.james.mailbox.model.Cid;
-import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.metrics.api.MetricFactory;
 import org.apache.james.metrics.api.TimeMetric;
-import org.apache.james.util.OptionalUtils;
-import org.apache.mailet.Mail;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.github.fge.lambdas.Throwing;
-import com.github.fge.lambdas.functions.ThrowingFunction;
 import com.github.fge.lambdas.predicates.ThrowingPredicate;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
@@ -88,35 +73,29 @@ import com.google.common.collect.ImmutableList;
 public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private static final Logger LOG = LoggerFactory.getLogger(SetMailboxesCreationProcessor.class);
-    private final MIMEMessageConverter mimeMessageConverter;
-    private final MailSpool mailSpool;
-    private final MailFactory mailFactory;
     private final MessageFactory messageFactory;
     private final SystemMailboxesProvider systemMailboxesProvider;
     private final AttachmentManager attachmentManager;
     private final MetricFactory metricFactory;
     private final MailboxManager mailboxManager;
     private final MailboxId.Factory mailboxIdFactory;
+    private final MessageAppender messageAppender;
+    private final MessageSender messageSender;
     
     @VisibleForTesting @Inject
-    SetMessagesCreationProcessor(MIMEMessageConverter mimeMessageConverter,
-                                 MailSpool mailSpool,
-                                 MailFactory mailFactory,
-                                 MessageFactory messageFactory,
-                                 SystemMailboxesProvider systemMailboxesProvider,
-                                 AttachmentManager attachmentManager, 
+    SetMessagesCreationProcessor(MessageFactory messageFactory, SystemMailboxesProvider systemMailboxesProvider,
+                                 AttachmentManager attachmentManager,
                                  MetricFactory metricFactory,
                                  MailboxManager mailboxManager,
-                                 MailboxId.Factory mailboxIdFactory) {
-        this.mimeMessageConverter = mimeMessageConverter;
-        this.mailSpool = mailSpool;
-        this.mailFactory = mailFactory;
+                                 MailboxId.Factory mailboxIdFactory, MessageAppender messageAppender, MessageSender messageSender) {
         this.messageFactory = messageFactory;
         this.systemMailboxesProvider = systemMailboxesProvider;
         this.attachmentManager = attachmentManager;
         this.metricFactory = metricFactory;
         this.mailboxManager = mailboxManager;
         this.mailboxIdFactory = mailboxIdFactory;
+        this.messageAppender = messageAppender;
+        this.messageSender = messageSender;
     }
 
     @Override
@@ -279,8 +258,10 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         if (!isRequestForSending(entry.getValue(), session)) {
             throw new IllegalStateException("Messages for everything but outbox should have been filtered earlier");
         }
-        MetaDataWithContent newMessage = createMessageInOutbox(entry, outbox, session);
-        return sendMessage(entry.getCreationId(), newMessage, session);
+        MetaDataWithContent newMessage = messageAppender.createMessageInMailbox(entry, outbox, session);
+        Message jmapMessage = messageFactory.fromMetaDataWithContent(newMessage);
+        messageSender.sendMessage(jmapMessage, newMessage, session);
+        return new ValueWithId.MessageWithId(entry.getCreationId(), jmapMessage);
     }
     
     private boolean isAppendToMailboxWithRole(Role role, CreationMessage entry, MailboxSession mailboxSession) throws MailboxException {
@@ -318,81 +299,5 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     private boolean isRequestForSending(CreationMessage creationMessage, MailboxSession session) throws MailboxException {
         return isAppendToMailboxWithRole(Role.OUTBOX, creationMessage, session);
     }
-    
-    private MetaDataWithContent createMessageInOutbox(MessageWithId.CreationMessageEntry createdEntry,
-                                                      MessageManager outbox,
-                                                      MailboxSession session) throws MailboxException {
-        ImmutableList<MessageAttachment> messageAttachments = getMessageAttachments(session, createdEntry.getValue().getAttachments());
-        byte[] messageContent = mimeMessageConverter.convert(createdEntry, messageAttachments);
-        SharedByteArrayInputStream content = new SharedByteArrayInputStream(messageContent);
-        Date internalDate = Date.from(createdEntry.getValue().getDate().toInstant());
-
-        Keywords keywords = createdEntry.getValue()
-            .getKeywords()
-            .orElse(Keywords.DEFAULT_VALUE);
-        boolean notRecent = false;
-
-        ComposedMessageId message = outbox.appendMessage(content, internalDate, session, notRecent, keywords.asFlags());
-
-        return MetaDataWithContent.builder()
-                .uid(message.getUid())
-                .keywords(keywords)
-                .internalDate(internalDate.toInstant())
-                .sharedContent(content)
-                .size(messageContent.length)
-                .attachments(messageAttachments)
-                .mailboxId(outbox.getId())
-                .messageId(message.getMessageId())
-                .build();
-    }
 
-    private ImmutableList<MessageAttachment> getMessageAttachments(MailboxSession session, ImmutableList<Attachment> attachments) throws MailboxException {
-        ThrowingFunction<Attachment, Optional<MessageAttachment>> toMessageAttachment = att -> messageAttachment(session, att);
-        return attachments.stream()
-            .map(Throwing.function(toMessageAttachment).sneakyThrow())
-            .flatMap(OptionalUtils::toStream)
-            .collect(Guavate.toImmutableList());
-    }
-
-    private Optional<MessageAttachment> messageAttachment(MailboxSession session, Attachment attachment) throws MailboxException {
-        try {
-            return Optional.of(MessageAttachment.builder()
-                    .attachment(attachmentManager.getAttachment(AttachmentId.from(attachment.getBlobId().getRawValue()), session))
-                    .name(attachment.getName().orElse(null))
-                    .cid(attachment.getCid().map(Cid::from).orElse(null))
-                    .isInline(attachment.isIsInline())
-                    .build());
-        } catch (AttachmentNotFoundException e) {
-            // should not happen (checked before)
-            LOG.error(String.format("Attachment %s not found", attachment.getBlobId()), e);
-            return Optional.empty();
-        } catch (IllegalStateException e) {
-            LOG.error(String.format("Attachment %s is not well-formed", attachment.getBlobId()), e);
-            return Optional.empty();
-        }
-    }
-
-    private MessageWithId sendMessage(CreationMessageId creationId, MetaDataWithContent message, MailboxSession session) throws MailboxException, MessagingException {
-        Message jmapMessage = messageFactory.fromMetaDataWithContent(message);
-        sendMessage(message, jmapMessage, session);
-        return new MessageWithId(creationId, jmapMessage);
-    }
-    
-    private void sendMessage(MetaDataWithContent message, Message jmapMessage, MailboxSession session) throws MessagingException {
-        Mail mail = buildMessage(message, jmapMessage);
-        try {
-            MailMetadata metadata = new MailMetadata(jmapMessage.getId(), session.getUser().getUserName());
-            mailSpool.send(mail, metadata);
-        } finally {
-            LifecycleUtil.dispose(mail);
-        }
-    }
-
-    private Mail buildMessage(MetaDataWithContent message, Message jmapMessage) throws MessagingException {
-        try {
-            return mailFactory.build(message, jmapMessage);
-        } catch (IOException e) {
-            throw new MessagingException("error building message to send", e);
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/4dbe064d/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 8618b11..25ece63 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
@@ -127,6 +127,8 @@ public class SetMessagesCreationProcessorTest {
 
     @Rule
     public ExpectedException expectedException = ExpectedException.none();
+    private MessageAppender messageAppender;
+    private MessageSender messageSender;
 
     @Before
     public void setUp() throws MailboxException {
@@ -146,7 +148,16 @@ public class SetMessagesCreationProcessorTest {
         fakeSystemMailboxesProvider = new TestSystemMailboxesProvider(() -> optionalOutbox, () -> optionalDrafts);
         session = new MockMailboxSession(USER);
         mimeMessageConverter = new MIMEMessageConverter();
-        sut = new SetMessagesCreationProcessor(mimeMessageConverter, mockedMailSpool, mockedMailFactory, messageFactory, fakeSystemMailboxesProvider, mockedAttachmentManager, new NoopMetricFactory(), mockedMailboxManager, mockedMailboxIdFactory);
+        messageAppender = new MessageAppender(mockedAttachmentManager, mimeMessageConverter);
+        messageSender = new MessageSender(mockedMailSpool, mockedMailFactory);
+        sut = new SetMessagesCreationProcessor(messageFactory,
+            fakeSystemMailboxesProvider,
+            mockedAttachmentManager,
+            new NoopMetricFactory(),
+            mockedMailboxManager,
+            mockedMailboxIdFactory,
+            messageAppender,
+            messageSender);
         
         outbox = mock(MessageManager.class);
         when(mockedMailboxIdFactory.fromString(OUTBOX_ID.serialize()))
@@ -230,7 +241,7 @@ public class SetMessagesCreationProcessorTest {
     @Test
     public void processShouldReturnNonEmptyCreatedWhenRequestHasNonEmptyCreate() throws MailboxException {
         // Given
-        sut = new SetMessagesCreationProcessor(mimeMessageConverter, mockedMailSpool, mockedMailFactory, messageFactory, fakeSystemMailboxesProvider, mockedAttachmentManager, new NoopMetricFactory(), mockedMailboxManager, mockedMailboxIdFactory);
+        sut = new SetMessagesCreationProcessor(messageFactory, fakeSystemMailboxesProvider, mockedAttachmentManager, new NoopMetricFactory(), mockedMailboxManager, mockedMailboxIdFactory, messageAppender, messageSender);
 
         // When
         SetMessagesResponse result = sut.process(createMessageInOutbox, session);
@@ -245,7 +256,10 @@ public class SetMessagesCreationProcessorTest {
     public void processShouldReturnErrorWhenOutboxNotFound() {
         // Given
         TestSystemMailboxesProvider doNotProvideOutbox = new TestSystemMailboxesProvider(Optional::empty, () -> optionalDrafts);
-        SetMessagesCreationProcessor sut = new SetMessagesCreationProcessor(mimeMessageConverter, mockedMailSpool, mockedMailFactory, messageFactory, doNotProvideOutbox, mockedAttachmentManager, new NoopMetricFactory(), mockedMailboxManager, mockedMailboxIdFactory);
+        SetMessagesCreationProcessor sut = new SetMessagesCreationProcessor(messageFactory, doNotProvideOutbox,
+            mockedAttachmentManager, new NoopMetricFactory(), mockedMailboxManager, mockedMailboxIdFactory,
+            messageAppender,
+            messageSender);
         // When
         SetMessagesResponse actual = sut.process(createMessageInOutbox, session);
         


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


[09/19] james-project git commit: JAMES-2214 s/validate/assert/ in MessageSender

Posted by ad...@apache.org.
JAMES-2214 s/validate/assert/ in MessageSender


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

Branch: refs/heads/master
Commit: 2b22852718246723887cbaf371cf49846a0249aa
Parents: 46e520e
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 16:24:00 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:45 2017 +0700

----------------------------------------------------------------------
 .../main/java/org/apache/james/jmap/methods/MessageSender.java   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/2b228527/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
index ab360ea..6a1a089 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MessageSender.java
@@ -47,7 +47,7 @@ public class MessageSender {
     public void sendMessage(Message jmapMessage,
                             MessageFactory.MetaDataWithContent message,
                             MailboxSession session) throws MailboxException, MessagingException {
-        validateUserIsInSenders(jmapMessage, session);
+        assertUserIsInSenders(jmapMessage, session);
         Mail mail = buildMessage(message, jmapMessage);
         try {
             MailMetadata metadata = new MailMetadata(jmapMessage.getId(), session.getUser().getUserName());
@@ -65,7 +65,7 @@ public class MessageSender {
         }
     }
 
-    private void validateUserIsInSenders(Message message, MailboxSession session) throws MailboxSendingNotAllowedException {
+    private void assertUserIsInSenders(Message message, MailboxSession session) throws MailboxSendingNotAllowedException {
         String allowedSender = session.getUser().getUserName();
         if (!isAllowedFromAddress(message, allowedSender)) {
             throw new MailboxSendingNotAllowedException(allowedSender);


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


[13/19] james-project git commit: JAMES-2214 s/validate/assert/ for SetMessageCreationProcessor check methods

Posted by ad...@apache.org.
JAMES-2214 s/validate/assert/ for SetMessageCreationProcessor check methods


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

Branch: refs/heads/master
Commit: 264ffd72c194fcb113a7722df0c0cc6180d40626
Parents: 8ad6ba6
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 15:59:55 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 18:05:45 2017 +0700

----------------------------------------------------------------------
 .../jmap/methods/SetMessagesCreationProcessor.java    |  4 ++--
 .../methods/SetMessagesCreationProcessorTest.java     | 14 +++++++-------
 2 files changed, 9 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/264ffd72/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 4b0e38b..ac12072 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
@@ -110,7 +110,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private void handleCreate(CreationMessageEntry create, Builder responseBuilder, MailboxSession mailboxSession) {
         try {
-            validateIsUserOwnerOfMailboxes(create, mailboxSession);
+            assertIsUserOwnerOfMailboxes(create, mailboxSession);
             performCreate(create, responseBuilder, mailboxSession);
         } catch (MailboxSendingNotAllowedException e) {
             responseBuilder.notCreated(create.getCreationId(), 
@@ -217,7 +217,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         attachmentChecker.assertAttachmentsExist(entry, session);
     }
 
-    @VisibleForTesting void validateIsUserOwnerOfMailboxes(CreationMessageEntry entry, MailboxSession session) throws MailboxNotOwnedException {
+    @VisibleForTesting void assertIsUserOwnerOfMailboxes(CreationMessageEntry entry, MailboxSession session) throws MailboxNotOwnedException {
         if (containsMailboxNotOwn(entry.getValue().getMailboxIds(), session)) {
             throw new MailboxNotOwnedException();
         }

http://git-wip-us.apache.org/repos/asf/james-project/blob/264ffd72/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 8a55816..0d8a9cb 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
@@ -322,11 +322,11 @@ public class SetMessagesCreationProcessorTest {
         CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
         CreationMessageEntry entry = new CreationMessageEntry(creationMessageId, creationMessageBuilder.mailboxId(mailboxId.serialize()).build());
 
-        assertThatThrownBy(() -> sut.validateIsUserOwnerOfMailboxes(entry, session));
+        assertThatThrownBy(() -> sut.assertIsUserOwnerOfMailboxes(entry, session));
     }
 
     @Test
-    public void validateIsUserOwnerOfMailboxesShouldThrowWhenRetrievingMailboxPathFails() throws Exception {
+    public void assertIsUserOwnerOfMailboxesShouldThrowWhenRetrievingMailboxPathFails() throws Exception {
         CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
         InMemoryId mailboxId = InMemoryId.of(6789);
         MessageManager mailbox = mock(MessageManager.class);
@@ -339,11 +339,11 @@ public class SetMessagesCreationProcessorTest {
 
         CreationMessageEntry entry = new CreationMessageEntry(creationMessageId, creationMessageBuilder.mailboxId(mailboxId.serialize()).build());
 
-        assertThatThrownBy(() -> sut.validateIsUserOwnerOfMailboxes(entry, session));
+        assertThatThrownBy(() -> sut.assertIsUserOwnerOfMailboxes(entry, session));
     }
 
     @Test
-    public void validateIsUserOwnerOfMailboxesShouldThrowWhenUserIsNotTheOwnerOfTheMailbox() throws Exception {
+    public void assertIsUserOwnerOfMailboxesShouldThrowWhenUserIsNotTheOwnerOfTheMailbox() throws Exception {
         CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
         InMemoryId mailboxId = InMemoryId.of(6789);
         MessageManager mailbox = mock(MessageManager.class);
@@ -357,12 +357,12 @@ public class SetMessagesCreationProcessorTest {
 
         CreationMessageEntry entry = new CreationMessageEntry(creationMessageId, creationMessageBuilder.mailboxId(mailboxId.serialize()).build());
 
-        assertThatThrownBy(() -> sut.validateIsUserOwnerOfMailboxes(entry, session))
+        assertThatThrownBy(() -> sut.assertIsUserOwnerOfMailboxes(entry, session))
             .isInstanceOf(MailboxNotOwnedException.class);
     }
 
     @Test
-    public void validateIsUserOwnerOfMailboxesShouldNotThrowWhenUserIsTheOwnerOfTheMailbox() throws Exception {
+    public void assertIsUserOwnerOfMailboxesShouldNotThrowWhenUserIsTheOwnerOfTheMailbox() throws Exception {
         CreationMessageId creationMessageId = CreationMessageId.of("anything-really");
         InMemoryId mailboxId = InMemoryId.of(6789);
         MessageManager mailbox = mock(MessageManager.class);
@@ -376,7 +376,7 @@ public class SetMessagesCreationProcessorTest {
 
         CreationMessageEntry entry = new CreationMessageEntry(creationMessageId, creationMessageBuilder.mailboxId(mailboxId.serialize()).build());
 
-        sut.validateIsUserOwnerOfMailboxes(entry, session);
+        sut.assertIsUserOwnerOfMailboxes(entry, 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


[03/19] james-project git commit: JAMES-2214 Remove redundant OUTBOX checking

Posted by ad...@apache.org.
JAMES-2214 Remove redundant OUTBOX checking

When we reached the code about saving message in Outbox, we already enforced the message should only be in outbox, hence that code was not needed.


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

Branch: refs/heads/master
Commit: d324caac0d6ac35460893f2ee5ccc8d991ea94b2
Parents: e3ffd2b
Author: benwa <bt...@linagora.com>
Authored: Mon Nov 13 09:46:33 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Nov 15 17:59:48 2017 +0700

----------------------------------------------------------------------
 .../james/jmap/methods/SetMessagesCreationProcessor.java    | 9 +--------
 .../java/org/apache/james/jmap/model/CreationMessage.java   | 2 +-
 2 files changed, 2 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/d324caac/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 045bf37..e2d13da 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
@@ -234,9 +234,6 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private MessageWithId handleOutboxMessages(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MessagingException {
         MessageManager outbox = getMailboxWithRole(session, Role.OUTBOX).orElseThrow(() -> new MailboxNotFoundException(Role.OUTBOX.serialize()));
-        if (!isRequestForSending(entry.getValue(), session)) {
-            throw new IllegalStateException("Messages for everything but outbox should have been filtered earlier");
-        }
         MetaDataWithContent newMessage = messageAppender.createMessageInMailbox(entry, outbox, session);
         Message jmapMessage = messageFactory.fromMetaDataWithContent(newMessage);
         messageSender.sendMessage(jmapMessage, newMessage, session);
@@ -245,7 +242,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     
     private boolean isAppendToMailboxWithRole(Role role, CreationMessage entry, MailboxSession mailboxSession) throws MailboxException {
         return getMailboxWithRole(mailboxSession, role)
-                .map(entry::isInOnly)
+                .map(entry::isOnlyIn)
                 .orElse(false);
     }
 
@@ -275,8 +272,4 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
                 .collect(Collectors.toSet());
     }
 
-    private boolean isRequestForSending(CreationMessage creationMessage, MailboxSession session) throws MailboxException {
-        return isAppendToMailboxWithRole(Role.OUTBOX, creationMessage, session);
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/d324caac/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 73bbf9d..097d172 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
@@ -371,7 +371,7 @@ public class CreationMessage {
         return mailboxIds.contains(mailbox.getId().serialize());
     }
 
-    public boolean isInOnly(MessageManager mailbox) {
+    public boolean isOnlyIn(MessageManager mailbox) {
         return isIn(mailbox)
             && mailboxIds.size() == 1;
     }


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