You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2017/10/03 00:54:28 UTC
[1/6] james-project git commit: JAMES-2162 Introduce GuavaUtils
Repository: james-project
Updated Branches:
refs/heads/master f458495a0 -> 651a03db6
JAMES-2162 Introduce GuavaUtils
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/6e9ad73a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/6e9ad73a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/6e9ad73a
Branch: refs/heads/master
Commit: 6e9ad73afc6d7ec13aeb8bf3e82861b901f3cabe
Parents: f458495
Author: benwa <bt...@linagora.com>
Authored: Mon Oct 2 17:30:54 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Tue Oct 3 07:51:58 2017 +0700
----------------------------------------------------------------------
.../java/org/apache/james/util/GuavaUtils.java | 37 +++++++++
.../org/apache/james/util/GuavaUtilsTest.java | 80 ++++++++++++++++++++
2 files changed, 117 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/6e9ad73a/server/container/util-java8/src/main/java/org/apache/james/util/GuavaUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/GuavaUtils.java b/server/container/util-java8/src/main/java/org/apache/james/util/GuavaUtils.java
new file mode 100644
index 0000000..518ead1
--- /dev/null
+++ b/server/container/util-java8/src/main/java/org/apache/james/util/GuavaUtils.java
@@ -0,0 +1,37 @@
+/****************************************************************
+ * 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.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableListMultimap;
+
+public class GuavaUtils {
+ public static <K, V> ImmutableListMultimap<K, V> toMultimap(Map<K, List<V>> rights) {
+ return rights.entrySet()
+ .stream()
+ .flatMap(e -> e.getValue().stream().map(right -> Pair.of(e.getKey(), right)))
+ .collect(Guavate.toImmutableListMultimap(Pair::getKey, Pair::getValue));
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6e9ad73a/server/container/util-java8/src/test/java/org/apache/james/util/GuavaUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/GuavaUtilsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/GuavaUtilsTest.java
new file mode 100644
index 0000000..3702e5e
--- /dev/null
+++ b/server/container/util-java8/src/test/java/org/apache/james/util/GuavaUtilsTest.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.List;
+
+import org.junit.Test;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableListMultimap;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
+
+public class GuavaUtilsTest {
+
+ @Test
+ public void toMultimapShouldAcceptEmptyMaps() {
+ assertThat(GuavaUtils.toMultimap(ImmutableMap
+ .<String, List<String>>builder()
+ .build())
+ .asMap())
+ .isEqualTo(ImmutableMap.of());
+ }
+
+ @Test
+ public void toMultimapShouldAcceptSingleValuesMaps() {
+ assertThat(GuavaUtils.toMultimap(ImmutableMap
+ .<String, List<String>>builder()
+ .put("k1", ImmutableList.of("v1"))
+ .put("k2", ImmutableList.of("v2"))
+ .build())
+ .asMap())
+ .isEqualTo(ImmutableListMultimap.of(
+ "k1", "v1",
+ "k2", "v2")
+ .asMap());
+ }
+
+ @Test
+ public void toMultimapShouldAcceptMultiplesValuesMaps() {
+ assertThat(GuavaUtils.toMultimap(ImmutableMap
+ .<String, List<String>>builder()
+ .put("k1", ImmutableList.of("v1"))
+ .put("k2", ImmutableList.of("v2", "v2.1"))
+ .build())
+ .asMap())
+ .isEqualTo(ImmutableListMultimap.of(
+ "k1", "v1",
+ "k2", "v2",
+ "k2", "v2.1")
+ .asMap());
+ }
+
+ @Test
+ public void shouldStripEntriesWithEmptyList() {
+ assertThat(GuavaUtils.toMultimap(ImmutableMap
+ .<String, List<String>>builder()
+ .put("k1", ImmutableList.of())
+ .build())
+ .asMap())
+ .isEqualTo(ImmutableListMultimap.of().asMap());
+ }
+}
\ 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
[5/6] james-project git commit: JAMES-2162 Rename confusing optional
method
Posted by bt...@apache.org.
JAMES-2162 Rename confusing optional method
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/23dd9053
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/23dd9053
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/23dd9053
Branch: refs/heads/master
Commit: 23dd9053ab65bbde40e9383ccd9ebe1a580576f4
Parents: 69d783e
Author: benwa <bt...@linagora.com>
Authored: Mon Oct 2 15:58:23 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Tue Oct 3 07:52:17 2017 +0700
----------------------------------------------------------------------
.../james/mailbox/cassandra/mail/CassandraBlobsDAO.java | 2 +-
.../mailbox/cassandra/mail/CassandraMailboxMapper.java | 2 +-
.../mailbox/cassandra/mail/CassandraMessageMapper.java | 3 ++-
.../src/main/java/org/apache/james/util/OptionalUtils.java | 2 +-
.../test/java/org/apache/james/util/OptionalUtilsTest.java | 9 +++++----
5 files changed, 10 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/23dd9053/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraBlobsDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraBlobsDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraBlobsDAO.java
index 031a429..b96e5c4 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraBlobsDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraBlobsDAO.java
@@ -168,7 +168,7 @@ public class CassandraBlobsDAO {
private byte[] concatenateDataParts(Stream<BlobPart> blobParts) {
ImmutableList<byte[]> parts = blobParts
- .map(blobPart -> OptionalUtils.ifEmpty(
+ .map(blobPart -> OptionalUtils.peekOnEmpty(
blobPart.row,
() -> LOGGER.warn("Missing blob part for blobId {} and position {}", blobPart.blobId, blobPart.position)))
.flatMap(OptionalUtils::toStream)
http://git-wip-us.apache.org/repos/asf/james-project/blob/23dd9053/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
index 1b6d2f8..d9d5c10 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
@@ -141,7 +141,7 @@ public class CassandraMailboxMapper implements MailboxMapper {
private CompletableFuture<Optional<SimpleMailbox>> retrieveMailbox(CassandraMailboxPathDAO.CassandraIdAndPath idAndPath) {
return retrieveMailbox(idAndPath.getCassandraId())
- .thenApply(optional -> OptionalUtils.ifEmpty(optional,
+ .thenApply(optional -> OptionalUtils.peekOnEmpty(optional,
() -> LOGGER.warn("Could not retrieve mailbox {} with path {} in mailbox table.", idAndPath.getCassandraId(), idAndPath.getMailboxPath())));
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/23dd9053/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
index 957595a..cf38640 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
@@ -27,6 +27,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
+
import javax.mail.Flags;
import javax.mail.Flags.Flag;
@@ -225,7 +226,7 @@ public class CassandraMessageMapper implements MessageMapper {
private CompletableFuture<Optional<ComposedMessageIdWithMetaData>> retrieveComposedId(CassandraId mailboxId, MessageUid uid) {
return messageIdDAO.retrieve(mailboxId, uid)
- .thenApply(optional -> OptionalUtils.ifEmpty(optional,
+ .thenApply(optional -> OptionalUtils.peekOnEmpty(optional,
() -> LOGGER.warn("Could not retrieve message {} {}", mailboxId, uid)));
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/23dd9053/server/container/util-java8/src/main/java/org/apache/james/util/OptionalUtils.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/OptionalUtils.java b/server/container/util-java8/src/main/java/org/apache/james/util/OptionalUtils.java
index 709981b..66628ba 100644
--- a/server/container/util-java8/src/main/java/org/apache/james/util/OptionalUtils.java
+++ b/server/container/util-java8/src/main/java/org/apache/james/util/OptionalUtils.java
@@ -28,7 +28,7 @@ public class OptionalUtils {
void perform();
}
- public static <T> Optional<T> ifEmpty(Optional<T> optional, Operation operation) {
+ public static <T> Optional<T> peekOnEmpty(Optional<T> optional, Operation operation) {
if (!optional.isPresent()) {
operation.perform();
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/23dd9053/server/container/util-java8/src/test/java/org/apache/james/util/OptionalUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/OptionalUtilsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/OptionalUtilsTest.java
index 79b993c..a270469 100644
--- a/server/container/util-java8/src/test/java/org/apache/james/util/OptionalUtilsTest.java
+++ b/server/container/util-java8/src/test/java/org/apache/james/util/OptionalUtilsTest.java
@@ -19,6 +19,7 @@
package org.apache.james.util;
import static org.assertj.core.api.Assertions.assertThat;
+
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
@@ -35,7 +36,7 @@ public class OptionalUtilsTest {
@Test
public void ifEmptyShouldPreserveValueOfEmptyOptionals() {
- Optional<Object> expected = OptionalUtils.ifEmpty(Optional.empty(), () -> { });
+ Optional<Object> expected = OptionalUtils.peekOnEmpty(Optional.empty(), () -> { });
assertThat(expected).isEmpty();
}
@@ -43,7 +44,7 @@ public class OptionalUtilsTest {
@Test
public void ifEmptyShouldPreserveValueOfPresentOptionals() {
String value = "value";
- Optional<String> expected = OptionalUtils.ifEmpty(Optional.of(value), () -> { });
+ Optional<String> expected = OptionalUtils.peekOnEmpty(Optional.of(value), () -> { });
assertThat(expected).contains(value);
}
@@ -52,7 +53,7 @@ public class OptionalUtilsTest {
public void ifEmptyShouldPerformOperationIfEmpty() {
AtomicInteger operationCounter = new AtomicInteger(0);
- OptionalUtils.ifEmpty(Optional.empty(), operationCounter::incrementAndGet);
+ OptionalUtils.peekOnEmpty(Optional.empty(), operationCounter::incrementAndGet);
assertThat(operationCounter.get()).isEqualTo(1);
}
@@ -61,7 +62,7 @@ public class OptionalUtilsTest {
public void ifEmptyShouldNotPerformOperationIfPresent() {
AtomicInteger operationCounter = new AtomicInteger(0);
- OptionalUtils.ifEmpty(Optional.of("value"), operationCounter::incrementAndGet);
+ OptionalUtils.peekOnEmpty(Optional.of("value"), operationCounter::incrementAndGet);
assertThat(operationCounter.get()).isEqualTo(0);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[6/6] james-project git commit: JAMES-2147 Add mentions of JIRA
labels on the website
Posted by bt...@apache.org.
JAMES-2147 Add mentions of JIRA labels on the website
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/651a03db
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/651a03db
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/651a03db
Branch: refs/heads/master
Commit: 651a03db6bf957853cf122d0427f0130b48c18e3
Parents: 23dd905
Author: benwa <bt...@linagora.com>
Authored: Fri Sep 22 17:23:33 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Tue Oct 3 07:53:12 2017 +0700
----------------------------------------------------------------------
src/homepage/index.html | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/651a03db/src/homepage/index.html
----------------------------------------------------------------------
diff --git a/src/homepage/index.html b/src/homepage/index.html
index ab42cf1..fd9d076 100644
--- a/src/homepage/index.html
+++ b/src/homepage/index.html
@@ -175,7 +175,20 @@ WHAT WILL YOU TRY:</b><br>
<b>Sources on Git:</b>
<br/>Read our sources from the <a href="git://git.apache.org/james-project.git" class="comm" alt="James Git sources">Apache Git</a>.<br/>
You can also come and interact with us on <a href="https://github.com/apache/james-project" class="comm" alt="James on GitHub">GitHub</a>.<br/>
- Here are some more instructions to <a href="/contribute.html" class="comm" alt="Contributing to James: guidelines">get starting contributing</a>.
+ </span>
+ </li>
+ <li class="post-template center-icon">
+ <a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20JAMES%20AND%20resolution%20%3D%20Unresolved%20AND%20labels%20%3D%20newbie%20ORDER%20BY%20priority%20DESC%2C%20updated%20DESC" alt="contribute to the code"><span class="icon fa-cogs"></span></a>
+ <span class="details">
+ <b>Get started and contribute to this project:</b>
+ <br/>James is a project that lives from the contributions of its community! Read the <a href="/contribute.html" class="comm" alt="Contributing to James: guidelines">contributing guidelines</a>.
+ <br/>We more than welcome <b>articles</b> and <b>blog posts</b> about James. Contact us by <a href="https://james.apache.org/mail.html" class="comm" alt="mailing lists">email</a> or on <a href="https://gitter.im/apache/james-project" class="comm" alt="Gitter chat room">Gitter</a> to share your experiences.
+ <br/><b>Documentation</b> is an easy way to get started, and more than wanted! Check out the <a class="comm" alt="Documentation" href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20JAMES%20AND%20resolution%20%3D%20Unresolved%20AND%20labels%20%3D%20documentation%20ORDER%20BY%20priority%20DESC%2C%20updated%20DESC">~documentation</a> label on JIRA.
+ <br/>And to get started with <b>code contributions</b>, search out the
+ <a class="comm" alt="Newbie tasks" href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20JAMES%20AND%20resolution%20%3D%20Unresolved%20AND%20labels%20%3D%20newbie%20ORDER%20BY%20priority%20DESC%2C%20updated%20DESC">~newbie</a>,
+ <a class="comm" alt="Easy fixes" href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20JAMES%20AND%20resolution%20%3D%20Unresolved%20AND%20labels%20%3D%20easyfix%20ORDER%20BY%20priority%20DESC%2C%20updated%20DESC">~easyfix</a>,
+ <a class="comm" alt="Cool features" href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20JAMES%20AND%20resolution%20%3D%20Unresolved%20AND%20labels%20%3D%20feature%20ORDER%20BY%20priority%20DESC%2C%20updated%20DESC">~feature</a> labels on JIRA</a>.
+ <br/>There is many other ways one can help us: packaging, communication, etc . . .
</span>
</li>
<li class="post-template center-icon">
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[4/6] james-project git commit: JAMES-2162 JMAP implementation for
reading GetMailboxes::sharedWith
Posted by bt...@apache.org.
JAMES-2162 JMAP implementation for reading GetMailboxes::sharedWith
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/0ac2d416
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/0ac2d416
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/0ac2d416
Branch: refs/heads/master
Commit: 0ac2d416aceaeaf8c3b0e2c0384bccbf52bedf3d
Parents: 672f24f
Author: benwa <bt...@linagora.com>
Authored: Wed Sep 27 17:42:30 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Tue Oct 3 07:52:12 2017 +0700
----------------------------------------------------------------------
.../james/mailbox/store/probe/ACLProbe.java | 28 ++++
.../james/cli/probe/impl/JmxMailboxProbe.java | 11 +-
.../org/apache/james/modules/ACLProbeImpl.java | 51 +++++++
.../org/apache/james/modules/MailboxModule.java | 1 +
.../apache/james/modules/MailboxProbeImpl.java | 1 -
.../integration/GetMailboxesMethodTest.java | 147 ++++++++++++++-----
.../apache/james/jmap/model/MailboxFactory.java | 5 +
.../james/jmap/model/mailbox/Mailbox.java | 25 +++-
.../james/jmap/model/mailbox/MailboxTest.java | 2 +-
9 files changed, 222 insertions(+), 49 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/0ac2d416/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/ACLProbe.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/ACLProbe.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/ACLProbe.java
new file mode 100644
index 0000000..986186e
--- /dev/null
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/ACLProbe.java
@@ -0,0 +1,28 @@
+/****************************************************************
+ * 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.mailbox.store.probe;
+
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights;
+import org.apache.james.mailbox.model.MailboxPath;
+
+public interface ACLProbe {
+ void replaceRights(MailboxPath mailboxPath, String targetUser, Rfc4314Rights rights) throws MailboxException;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/0ac2d416/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java
----------------------------------------------------------------------
diff --git a/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java b/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java
index ab9005a..ebc1f0e 100644
--- a/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java
+++ b/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java
@@ -23,9 +23,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Date;
+
import javax.mail.Flags;
import javax.management.MalformedObjectNameException;
+import org.apache.commons.lang.NotImplementedException;
import org.apache.james.adapter.mailbox.MailboxCopierManagementMBean;
import org.apache.james.adapter.mailbox.MailboxManagerManagementMBean;
import org.apache.james.adapter.mailbox.ReIndexerManagementMBean;
@@ -97,23 +99,20 @@ public class JmxMailboxProbe implements MailboxProbe, JmxProbe {
reIndexerManagement.reIndex();
}
-
@Override
public Mailbox getMailbox(String namespace, String user, String name) {
- return null;
+ throw new NotImplementedException();
}
-
@Override
public ComposedMessageId appendMessage(String username, MailboxPath mailboxPath, InputStream message,
Date internalDate, boolean isRecent, Flags flags) throws MailboxException {
- return null;
+ throw new NotImplementedException();
}
@Override
public Collection<String> listSubscriptions(String user) throws Exception {
- return null;
+ throw new NotImplementedException();
}
-
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/0ac2d416/server/container/guice/mailbox/src/main/java/org/apache/james/modules/ACLProbeImpl.java
----------------------------------------------------------------------
diff --git a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/ACLProbeImpl.java b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/ACLProbeImpl.java
new file mode 100644
index 0000000..a25c4d9
--- /dev/null
+++ b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/ACLProbeImpl.java
@@ -0,0 +1,51 @@
+/****************************************************************
+ * 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.modules;
+
+import javax.inject.Inject;
+
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MailboxACL.ACLCommand;
+import org.apache.james.mailbox.model.MailboxACL.EditMode;
+import org.apache.james.mailbox.model.MailboxACL.EntryKey;
+import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.store.probe.ACLProbe;
+import org.apache.james.utils.GuiceProbe;
+
+public class ACLProbeImpl implements GuiceProbe, ACLProbe {
+ private final MailboxManager mailboxManager;
+
+ @Inject
+ private ACLProbeImpl(MailboxManager mailboxManager) {
+ this.mailboxManager = mailboxManager;
+ }
+
+ @Override
+ public void replaceRights(MailboxPath mailboxPath, String targetUser, Rfc4314Rights rights) throws MailboxException {
+ MailboxSession mailboxSession = mailboxManager.createSystemSession(mailboxPath.getUser());
+
+ EntryKey key = EntryKey.createUser(targetUser);
+ ACLCommand mailboxACLCommand = new ACLCommand(key, EditMode.REPLACE, rights);
+ mailboxManager.applyRightsCommand(mailboxPath, mailboxACLCommand, mailboxSession);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/0ac2d416/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxModule.java b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxModule.java
index 48a9077..a91ada3 100644
--- a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxModule.java
+++ b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxModule.java
@@ -30,6 +30,7 @@ public class MailboxModule extends AbstractModule {
Multibinder<GuiceProbe> probeMultiBinder = Multibinder.newSetBinder(binder(), GuiceProbe.class);
probeMultiBinder.addBinding().to(MailboxProbeImpl.class);
probeMultiBinder.addBinding().to(QuotaProbesImpl.class);
+ probeMultiBinder.addBinding().to(ACLProbeImpl.class);
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/0ac2d416/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
----------------------------------------------------------------------
diff --git a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
index 6a9588f..b2462ee 100644
--- a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
+++ b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
@@ -49,7 +49,6 @@ import org.apache.james.utils.GuiceProbe;
import com.google.common.base.Throwables;
public class MailboxProbeImpl implements GuiceProbe, MailboxProbe {
-
private final MailboxManager mailboxManager;
private final MailboxMapperFactory mailboxMapperFactory;
private final SubscriptionManager subscriptionManager;
http://git-wip-us.apache.org/repos/asf/james-project/blob/0ac2d416/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMailboxesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMailboxesMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMailboxesMethodTest.java
index 60806e7..c9136f3 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMailboxesMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMailboxesMethodTest.java
@@ -24,9 +24,11 @@ import static com.jayway.restassured.config.EncoderConfig.encoderConfig;
import static com.jayway.restassured.config.RestAssuredConfig.newConfig;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isEmptyOrNullString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
@@ -43,21 +45,26 @@ import org.apache.james.GuiceJamesServer;
import org.apache.james.jmap.DefaultMailboxes;
import org.apache.james.jmap.HttpJmapAuthentication;
import org.apache.james.jmap.api.access.AccessToken;
+import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights;
+import org.apache.james.mailbox.model.MailboxACL.Right;
import org.apache.james.mailbox.model.MailboxConstants;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.store.mail.model.Mailbox;
+import org.apache.james.mailbox.store.probe.ACLProbe;
import org.apache.james.mailbox.store.probe.MailboxProbe;
+import org.apache.james.modules.ACLProbeImpl;
import org.apache.james.modules.MailboxProbeImpl;
import org.apache.james.probe.DataProbe;
-import org.apache.james.utils.JmapGuiceProbe;
import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.JmapGuiceProbe;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.http.ContentType;
@@ -65,6 +72,11 @@ import com.jayway.restassured.http.ContentType;
public abstract class GetMailboxesMethodTest {
private static final String NAME = "[0][0]";
private static final String ARGUMENTS = "[0][1]";
+ private static final String FIRST_MAILBOX = ARGUMENTS + ".list[0]";
+
+ public static final String READ = String.valueOf(Right.Read.asCharacter());
+ public static final String LOOKUP = String.valueOf(Right.Lookup.asCharacter());
+ public static final String ADMINISTER = String.valueOf(Right.Administer.asCharacter());
protected abstract GuiceJamesServer createJmapServer();
@@ -72,13 +84,15 @@ public abstract class GetMailboxesMethodTest {
private String username;
private GuiceJamesServer jmapServer;
private MailboxProbe mailboxProbe;
+ private ACLProbe aclProbe;
@Before
public void setup() throws Throwable {
jmapServer = createJmapServer();
jmapServer.start();
mailboxProbe = jmapServer.getProbe(MailboxProbeImpl.class);
-
+ aclProbe = jmapServer.getProbe(ACLProbeImpl.class);
+
RestAssured.requestSpecification = new RequestSpecBuilder()
.setContentType(ContentType.JSON)
.setAccept(ContentType.JSON)
@@ -195,7 +209,7 @@ public abstract class GetMailboxesMethodTest {
.statusCode(200)
.body(NAME, equalTo("mailboxes"))
.body(ARGUMENTS + ".list", hasSize(1))
- .body(ARGUMENTS + ".list[0].id", equalTo(mailboxId));
+ .body(FIRST_MAILBOX + ".id", equalTo(mailboxId));
}
@Test
@@ -235,6 +249,67 @@ public abstract class GetMailboxesMethodTest {
.body(ARGUMENTS + ".list", hasSize(7))
.body(ARGUMENTS + ".list.name", hasItems(expectedMailboxes.toArray()));
}
+
+ @Test
+ public void getMailboxesShouldReturnSharedWithProperty() throws Exception {
+ String mailboxName = "myMailbox";
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, mailboxName);
+ String targetUser1 = "toUser1@domain.com";
+ String targetUser2 = "toUser2@domain.com";
+ Mailbox myMailbox = mailboxProbe.getMailbox(MailboxConstants.USER_NAMESPACE, username, mailboxName);
+ aclProbe.replaceRights(myMailbox.generateAssociatedPath(), targetUser1, new Rfc4314Rights(Right.Read, Right.Administer));
+ aclProbe.replaceRights(myMailbox.generateAssociatedPath(), targetUser2, new Rfc4314Rights(Right.Read, Right.Lookup));
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMailboxes\", {\"ids\": [\"" + myMailbox.getMailboxId().serialize() + "\"]}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxes"))
+ .body(FIRST_MAILBOX + ".name", equalTo(mailboxName))
+ .body(FIRST_MAILBOX + ".sharedWith", hasEntry(targetUser1, ImmutableList.of(ADMINISTER, READ)))
+ .body(FIRST_MAILBOX + ".sharedWith", hasEntry(targetUser2, ImmutableList.of(LOOKUP, READ)));
+ }
+
+ @Test
+ public void getMailboxShouldReturnEmptySharedWithWhenNoDelegation() throws Exception {
+ String mailboxName = "myMailbox";
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, mailboxName);
+ Mailbox myMailbox = mailboxProbe.getMailbox(MailboxConstants.USER_NAMESPACE, username, mailboxName);
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMailboxes\", {\"ids\": [\"" + myMailbox.getMailboxId().serialize() + "\"]}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxes"))
+ .body(FIRST_MAILBOX + ".name", equalTo(mailboxName))
+ .body(FIRST_MAILBOX + ".sharedWith", is(ImmutableMap.of()));
+ }
+
+ @Test
+ public void nonHandledRightsShouldBeFilteredOut() throws Exception {
+ String mailboxName = "myMailbox";
+ mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, mailboxName);
+ String targetUser1 = "toUser1@domain.com";
+ Mailbox myMailbox = mailboxProbe.getMailbox(MailboxConstants.USER_NAMESPACE, username, mailboxName);
+ aclProbe.replaceRights(myMailbox.generateAssociatedPath(), targetUser1, new Rfc4314Rights(Right.Read, Right.Post));
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMailboxes\", {\"ids\": [\"" + myMailbox.getMailboxId().serialize() + "\"]}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxes"))
+ .body(FIRST_MAILBOX + ".name", equalTo(mailboxName))
+ .body(FIRST_MAILBOX + ".sharedWith", hasEntry(targetUser1, ImmutableList.of(READ)));
+ }
@Test
public void getMailboxesShouldErrorInvalidArgumentsWhenRequestIsInvalid() throws Exception {
@@ -325,19 +400,19 @@ public abstract class GetMailboxesMethodTest {
.statusCode(200)
.body(NAME, equalTo("mailboxes"))
.body(ARGUMENTS + ".list.name", hasItem("name"))
- .body(ARGUMENTS + ".list[0].parentId", nullValue())
- .body(ARGUMENTS + ".list[0].role", nullValue())
- .body(ARGUMENTS + ".list[0].sortOrder", equalTo(1000))
- .body(ARGUMENTS + ".list[0].mustBeOnlyMailbox", equalTo(false))
- .body(ARGUMENTS + ".list[0].mayReadItems", equalTo(false))
- .body(ARGUMENTS + ".list[0].mayAddItems", equalTo(false))
- .body(ARGUMENTS + ".list[0].mayRemoveItems", equalTo(false))
- .body(ARGUMENTS + ".list[0].mayCreateChild", equalTo(false))
- .body(ARGUMENTS + ".list[0].mayRename", equalTo(false))
- .body(ARGUMENTS + ".list[0].mayDelete", equalTo(false))
- .body(ARGUMENTS + ".list[0].totalMessages", equalTo(1))
- .body(ARGUMENTS + ".list[0].unreadMessages", equalTo(1))
- .body(ARGUMENTS + ".list[0].unreadThreads", equalTo(0));
+ .body(FIRST_MAILBOX + ".parentId", nullValue())
+ .body(FIRST_MAILBOX + ".role", nullValue())
+ .body(FIRST_MAILBOX + ".sortOrder", equalTo(1000))
+ .body(FIRST_MAILBOX + ".mustBeOnlyMailbox", equalTo(false))
+ .body(FIRST_MAILBOX + ".mayReadItems", equalTo(false))
+ .body(FIRST_MAILBOX + ".mayAddItems", equalTo(false))
+ .body(FIRST_MAILBOX + ".mayRemoveItems", equalTo(false))
+ .body(FIRST_MAILBOX + ".mayCreateChild", equalTo(false))
+ .body(FIRST_MAILBOX + ".mayRename", equalTo(false))
+ .body(FIRST_MAILBOX + ".mayDelete", equalTo(false))
+ .body(FIRST_MAILBOX + ".totalMessages", equalTo(1))
+ .body(FIRST_MAILBOX + ".unreadMessages", equalTo(1))
+ .body(FIRST_MAILBOX + ".unreadThreads", equalTo(0));
}
@Test
@@ -353,21 +428,21 @@ public abstract class GetMailboxesMethodTest {
.then()
.statusCode(200)
.body(NAME, equalTo("mailboxes"))
- .body(ARGUMENTS + ".list[0].id", not(isEmptyOrNullString()))
- .body(ARGUMENTS + ".list[0].name", nullValue())
- .body(ARGUMENTS + ".list[0].parentId", nullValue())
- .body(ARGUMENTS + ".list[0].role", nullValue())
- .body(ARGUMENTS + ".list[0].sortOrder", equalTo(1000))
- .body(ARGUMENTS + ".list[0].mustBeOnlyMailbox", nullValue())
- .body(ARGUMENTS + ".list[0].mayReadItems", nullValue())
- .body(ARGUMENTS + ".list[0].mayAddItems", nullValue())
- .body(ARGUMENTS + ".list[0].mayRemoveItems", nullValue())
- .body(ARGUMENTS + ".list[0].mayCreateChild", nullValue())
- .body(ARGUMENTS + ".list[0].mayRename", nullValue())
- .body(ARGUMENTS + ".list[0].mayDelete", nullValue())
- .body(ARGUMENTS + ".list[0].totalMessages", nullValue())
- .body(ARGUMENTS + ".list[0].unreadMessages", equalTo(0))
- .body(ARGUMENTS + ".list[0].unreadThreads", nullValue());
+ .body(FIRST_MAILBOX + ".id", not(isEmptyOrNullString()))
+ .body(FIRST_MAILBOX + ".name", nullValue())
+ .body(FIRST_MAILBOX + ".parentId", nullValue())
+ .body(FIRST_MAILBOX + ".role", nullValue())
+ .body(FIRST_MAILBOX + ".sortOrder", equalTo(1000))
+ .body(FIRST_MAILBOX + ".mustBeOnlyMailbox", nullValue())
+ .body(FIRST_MAILBOX + ".mayReadItems", nullValue())
+ .body(FIRST_MAILBOX + ".mayAddItems", nullValue())
+ .body(FIRST_MAILBOX + ".mayRemoveItems", nullValue())
+ .body(FIRST_MAILBOX + ".mayCreateChild", nullValue())
+ .body(FIRST_MAILBOX + ".mayRename", nullValue())
+ .body(FIRST_MAILBOX + ".mayDelete", nullValue())
+ .body(FIRST_MAILBOX + ".totalMessages", nullValue())
+ .body(FIRST_MAILBOX + ".unreadMessages", equalTo(0))
+ .body(FIRST_MAILBOX + ".unreadThreads", nullValue());
}
@Test
@@ -382,8 +457,8 @@ public abstract class GetMailboxesMethodTest {
.then()
.statusCode(200)
.body(NAME, equalTo("mailboxes"))
- .body(ARGUMENTS + ".list[0].id", not(isEmptyOrNullString()))
- .body(ARGUMENTS + ".list[0].name", nullValue());
+ .body(FIRST_MAILBOX + ".id", not(isEmptyOrNullString()))
+ .body(FIRST_MAILBOX + ".name", nullValue());
}
@Test
@@ -398,8 +473,8 @@ public abstract class GetMailboxesMethodTest {
.then()
.statusCode(200)
.body(NAME, equalTo("mailboxes"))
- .body(ARGUMENTS + ".list[0].id", not(isEmptyOrNullString()))
- .body(ARGUMENTS + ".list[0].name", nullValue());
+ .body(FIRST_MAILBOX + ".id", not(isEmptyOrNullString()))
+ .body(FIRST_MAILBOX + ".name", nullValue());
}
@Test
@@ -438,7 +513,7 @@ public abstract class GetMailboxesMethodTest {
.statusCode(200)
.body(NAME, equalTo("mailboxes"))
.body(ARGUMENTS + ".list", hasSize(1))
- .body(ARGUMENTS + ".list[0].role", equalTo(DefaultMailboxes.OUTBOX.toLowerCase(Locale.US)));
+ .body(FIRST_MAILBOX + ".role", equalTo(DefaultMailboxes.OUTBOX.toLowerCase(Locale.US)));
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/0ac2d416/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MailboxFactory.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MailboxFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MailboxFactory.java
index 23d327c..9890c85 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MailboxFactory.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MailboxFactory.java
@@ -24,6 +24,7 @@ import java.util.Optional;
import javax.inject.Inject;
import org.apache.james.jmap.model.mailbox.Mailbox;
+import org.apache.james.jmap.model.mailbox.Rights;
import org.apache.james.jmap.model.mailbox.Role;
import org.apache.james.jmap.model.mailbox.SortOrder;
import org.apache.james.mailbox.MailboxManager;
@@ -42,6 +43,7 @@ import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
public class MailboxFactory {
+ public static final boolean NO_RESET_RECENT = false;
private final MailboxManager mailboxManager;
public static class MailboxBuilder {
@@ -98,6 +100,8 @@ public class MailboxFactory {
MailboxPath mailboxPath = messageManager.getMailboxPath();
Optional<Role> role = Role.from(mailboxPath.getName());
MailboxCounters mailboxCounters = messageManager.getMailboxCounters(mailboxSession);
+ MessageManager.MetaData metaData = messageManager.getMetaData(NO_RESET_RECENT, mailboxSession, MessageManager.MetaData.FetchGroup.NO_COUNT);
+
return Mailbox.builder()
.id(messageManager.getId())
.name(getName(mailboxPath, mailboxSession))
@@ -106,6 +110,7 @@ public class MailboxFactory {
.unreadMessages(mailboxCounters.getUnseen())
.totalMessages(mailboxCounters.getCount())
.sortOrder(SortOrder.getSortOrder(role))
+ .sharedWith(Rights.fromACL(metaData.getACL()))
.build();
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/0ac2d416/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Mailbox.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Mailbox.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Mailbox.java
index cddb101..d0b8144 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Mailbox.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Mailbox.java
@@ -60,9 +60,11 @@ public class Mailbox {
private long unreadMessages;
private long totalThreads;
private long unreadThreads;
+ private Optional<Rights> sharedWith;
private Builder() {
parentId = Optional.empty();
+ sharedWith = Optional.empty();
}
public Builder id(MailboxId id) {
@@ -147,12 +149,17 @@ public class Mailbox {
return this;
}
+ public Builder sharedWith(Rights sharedWith) {
+ this.sharedWith = Optional.of(sharedWith);
+ return this;
+ }
+
public Mailbox build() {
Preconditions.checkState(!Strings.isNullOrEmpty(name), "'name' is mandatory");
Preconditions.checkState(id != null, "'id' is mandatory");
return new Mailbox(id, name, parentId, role, sortOrder, mustBeOnlyMailbox, mayReadItems, mayAddItems, mayRemoveItems, mayCreateChild, mayRename, mayDelete,
- totalMessages, unreadMessages, totalThreads, unreadThreads);
+ totalMessages, unreadMessages, totalThreads, unreadThreads, sharedWith.orElse(Rights.EMPTY));
}
}
@@ -172,10 +179,11 @@ public class Mailbox {
private final long unreadMessages;
private final long totalThreads;
private final long unreadThreads;
+ private final Rights sharedWith;
@VisibleForTesting Mailbox(MailboxId id, String name, Optional<MailboxId> parentId, Optional<Role> role, SortOrder sortOrder, boolean mustBeOnlyMailbox,
- boolean mayReadItems, boolean mayAddItems, boolean mayRemoveItems, boolean mayCreateChild, boolean mayRename, boolean mayDelete,
- long totalMessages, long unreadMessages, long totalThreads, long unreadThreads) {
+ boolean mayReadItems, boolean mayAddItems, boolean mayRemoveItems, boolean mayCreateChild, boolean mayRename, boolean mayDelete,
+ long totalMessages, long unreadMessages, long totalThreads, long unreadThreads, Rights sharedWith) {
this.id = id;
this.name = name;
@@ -193,6 +201,7 @@ public class Mailbox {
this.unreadMessages = unreadMessages;
this.totalThreads = totalThreads;
this.unreadThreads = unreadThreads;
+ this.sharedWith = sharedWith;
}
public MailboxId getId() {
@@ -259,6 +268,10 @@ public class Mailbox {
return unreadThreads;
}
+ public Rights getSharedWith() {
+ return sharedWith;
+ }
+
@Override
public final boolean equals(Object obj) {
if (obj instanceof Mailbox) {
@@ -278,7 +291,8 @@ public class Mailbox {
&& Objects.equals(this.totalMessages, other.totalMessages)
&& Objects.equals(this.unreadMessages, other.unreadMessages)
&& Objects.equals(this.totalThreads, other.totalThreads)
- && Objects.equals(this.unreadThreads, other.unreadThreads);
+ && Objects.equals(this.unreadThreads, other.unreadThreads)
+ && Objects.equals(this.sharedWith, other.sharedWith);
}
return false;
}
@@ -286,7 +300,8 @@ public class Mailbox {
@Override
public final int hashCode() {
return Objects.hash(id, name, parentId, role, sortOrder, mustBeOnlyMailbox, mayReadItems, mayAddItems,
- mayRemoveItems, mayCreateChild, mayRename, mayDelete, totalMessages, unreadMessages, totalThreads, unreadThreads);
+ mayRemoveItems, mayCreateChild, mayRename, mayDelete, totalMessages, unreadMessages, totalThreads,
+ unreadThreads, sharedWith);
}
@Override
http://git-wip-us.apache.org/repos/asf/james-project/blob/0ac2d416/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/MailboxTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/MailboxTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/MailboxTest.java
index 1ac869f..91275df 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/MailboxTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/MailboxTest.java
@@ -63,7 +63,7 @@ public class MailboxTest {
@Test
public void buildShouldWork() {
Mailbox expectedMailbox = new Mailbox(InMemoryId.of(1), "name", Optional.of(InMemoryId.of(0)), Optional.of(Role.DRAFTS), SortOrder.of(123),
- true, true, true, true, true, true, true, 456, 789, 741, 852);
+ true, true, true, true, true, true, true, 456, 789, 741, 852, Rights.EMPTY);
Mailbox mailbox = Mailbox.builder()
.id(InMemoryId.of(1))
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[2/6] james-project git commit: JAMES-2162 Introduce JMAP Rights
object
Posted by bt...@apache.org.
JAMES-2162 Introduce JMAP Rights object
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/672f24f1
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/672f24f1
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/672f24f1
Branch: refs/heads/master
Commit: 672f24f1e1034d02f9e11bfae0674a5d8409272d
Parents: 6e9ad73
Author: benwa <bt...@linagora.com>
Authored: Wed Sep 27 17:43:00 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Tue Oct 3 07:52:07 2017 +0700
----------------------------------------------------------------------
.../apache/james/mailbox/model/MailboxACL.java | 5 +
.../apache/james/jmap/model/mailbox/Rights.java | 240 +++++++++++++++++++
.../james/jmap/model/mailbox/RightsTest.java | 164 +++++++++++++
3 files changed, 409 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/672f24f1/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxACL.java
----------------------------------------------------------------------
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxACL.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxACL.java
index d1e1487..a831302 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxACL.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxACL.java
@@ -333,6 +333,11 @@ public class MailboxACL {
public Entry(String key, String value) throws UnsupportedRightException {
this(EntryKey.deserialize(key), Rfc4314Rights.fromSerializedRfc4314Rights(value));
}
+
+ public Entry(String key, Right... rights) throws UnsupportedRightException {
+ this(EntryKey.deserialize(key), new Rfc4314Rights(rights));
+ }
+
}
/**
http://git-wip-us.apache.org/repos/asf/james-project/blob/672f24f1/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Rights.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Rights.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Rights.java
new file mode 100644
index 0000000..d44e4d3
--- /dev/null
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Rights.java
@@ -0,0 +1,240 @@
+/****************************************************************
+ * 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.mailbox;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.BinaryOperator;
+
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.mailbox.model.MailboxACL.EntryKey;
+import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights;
+import org.apache.james.util.GuavaUtils;
+import org.apache.james.util.OptionalUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multimap;
+
+public class Rights {
+ public enum Right {
+ Administer(MailboxACL.Right.Administer),
+ Expunge(MailboxACL.Right.PerformExpunge),
+ Insert(MailboxACL.Right.Insert),
+ Lookup(MailboxACL.Right.Lookup),
+ Read(MailboxACL.Right.Read),
+ Seen(MailboxACL.Right.WriteSeenFlag),
+ DeleteMessages(MailboxACL.Right.DeleteMessages),
+ Write(MailboxACL.Right.Write);
+
+ private final MailboxACL.Right right;
+
+ Right(MailboxACL.Right right) {
+ this.right = right;
+ }
+
+ @JsonValue
+ public char asCharacter() {
+ return right.asCharacter();
+ }
+
+ public MailboxACL.Right toMailboxRight() {
+ return right;
+ }
+
+ public static Optional<Right> forRight(MailboxACL.Right right) {
+ return OptionalUtils.peekOnEmpty(
+ Arrays.stream(values())
+ .filter(jmapRight -> jmapRight.right == right)
+ .findAny(),
+ () -> LOGGER.warn("Non handled right '" + right + "'"));
+ }
+
+ public static Right forChar(char c) {
+ return Arrays.stream(values())
+ .filter(right -> right.asCharacter() == c)
+ .findAny()
+ .orElseThrow(() -> new IllegalArgumentException("No matching right for '" + c + "'"));
+ }
+ }
+
+ public static class Username {
+ private final String value;
+
+ // @JsonCreator
+ public Username(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof Username) {
+ Username username = (Username) o;
+
+ return Objects.equals(this.value, username.value);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(value);
+ }
+ }
+
+ public static class Builder {
+ private Multimap<Username, Right> rights;
+
+ public Builder() {
+ rights = ArrayListMultimap.create();
+ }
+
+ public Builder delegateTo(Username username, Right... rights) {
+ delegateTo(username, Arrays.asList(rights));
+ return this;
+ }
+
+ public Builder delegateTo(Username username, Collection<Right> rights) {
+ this.rights.putAll(username, rights);
+ return this;
+ }
+
+ public Builder combine(Builder builder) {
+ this.rights.putAll(builder.rights);
+ return this;
+ }
+
+ public Rights build() {
+ return new Rights(rights);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static Rights fromACL(MailboxACL acl) {
+ return acl.getEntries()
+ .entrySet()
+ .stream()
+ .filter(entry -> isSupported(entry.getKey()))
+ .map(Rights::toRightsBuilder)
+ .reduce(builder(), Builder::combine)
+ .build();
+ }
+
+ private static Builder toRightsBuilder(Map.Entry<EntryKey, MailboxACL.Rfc4314Rights> entry) {
+ return builder().delegateTo(
+ new Username(entry.getKey().getName()),
+ fromACL(entry.getValue()));
+ }
+
+ private static List<Right> fromACL(MailboxACL.Rfc4314Rights rights) {
+ return rights.list()
+ .stream()
+ .flatMap(right -> OptionalUtils.toStream(Right.forRight(right)))
+ .collect(Guavate.toImmutableList());
+ }
+
+ private static boolean isSupported(EntryKey key) {
+ if (key.isNegative()) {
+ LOGGER.info("Negative keys are not supported");
+ return false;
+ }
+ if (key.getNameType() != MailboxACL.NameType.user) {
+ LOGGER.info(key.getNameType() + " is not supported. Only 'user' is.");
+ return false;
+ }
+ return true;
+ }
+
+ public static final Rights EMPTY = new Rights(ArrayListMultimap.create());
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Rights.class);
+
+ private final Multimap<Username, Right> rights;
+
+ @JsonCreator
+ public Rights(Map<Username, List<Right>> rights) {
+ this(GuavaUtils.toMultimap(rights));
+ }
+
+ private Rights(Multimap<Username, Right> rights) {
+ this.rights = rights;
+ }
+
+ @JsonAnyGetter
+ public Map<Username, Collection<Right>> getRights() {
+ return rights.asMap();
+ }
+
+ public MailboxACL toMailboxAcl() {
+ BinaryOperator<MailboxACL> union = Throwing.binaryOperator(MailboxACL::union);
+
+ return rights.asMap()
+ .entrySet()
+ .stream()
+ .map(entry -> new MailboxACL(
+ ImmutableMap.of(
+ EntryKey.createUser(entry.getKey().value),
+ toMailboxAclRights(entry.getValue()))))
+ .reduce(MailboxACL.EMPTY, union);
+ }
+
+ private Rfc4314Rights toMailboxAclRights(Collection<Right> rights) {
+ BinaryOperator<Rfc4314Rights> union = Throwing.binaryOperator(Rfc4314Rights::union);
+
+ return rights.stream()
+ .map(Right::toMailboxRight)
+ .map(Throwing.function(Rfc4314Rights::new))
+ .reduce(new Rfc4314Rights(), union);
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof Rights) {
+ Rights that = (Rights) o;
+
+ return Objects.equals(this.rights, that.rights);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(rights);
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/672f24f1/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/RightsTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/RightsTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/RightsTest.java
new file mode 100644
index 0000000..dae6130
--- /dev/null
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/RightsTest.java
@@ -0,0 +1,164 @@
+/****************************************************************
+ * 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.mailbox;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.mailbox.model.MailboxACL.Entry;
+import org.apache.james.mailbox.model.MailboxACL.EntryKey;
+import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class RightsTest {
+
+ public static final boolean NEGATIVE = true;
+
+ @Test
+ public void rightsShouldMatchBeanContract() {
+ EqualsVerifier.forClass(Rights.class)
+ .allFieldsShouldBeUsed()
+ .verify();
+ }
+
+ @Test
+ public void usernameShouldMatchBeanContract() {
+ EqualsVerifier.forClass(Rights.Username.class)
+ .allFieldsShouldBeUsed()
+ .verify();
+ }
+
+ @Test
+ public void forCharShouldReturnRightWhenA() {
+ assertThat(Rights.Right.forChar('a'))
+ .isEqualTo(Rights.Right.Administer);
+ }
+
+ @Test
+ public void forCharShouldReturnRightWhenE() {
+ assertThat(Rights.Right.forChar('e'))
+ .isEqualTo(Rights.Right.Expunge);
+ }
+
+ @Test
+ public void forCharShouldReturnRightWhenI() {
+ assertThat(Rights.Right.forChar('i'))
+ .isEqualTo(Rights.Right.Insert);
+ }
+
+ @Test
+ public void forCharShouldReturnRightWhenL() {
+ assertThat(Rights.Right.forChar('l'))
+ .isEqualTo(Rights.Right.Lookup);
+ }
+
+ @Test
+ public void forCharShouldReturnRightWhenR() {
+ assertThat(Rights.Right.forChar('r'))
+ .isEqualTo(Rights.Right.Read);
+ }
+
+ @Test
+ public void forCharShouldReturnRightWhenW() {
+ assertThat(Rights.Right.forChar('w'))
+ .isEqualTo(Rights.Right.Write);
+ }
+
+ @Test
+ public void forCharShouldReturnRightWhenT() {
+ assertThat(Rights.Right.forChar('t'))
+ .isEqualTo(Rights.Right.DeleteMessages);
+ }
+
+ @Test
+ public void forCharShouldThrowOnUnsupportedRight() {
+ assertThatThrownBy(() -> Rights.Right.forChar('k'))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void fromACLShouldFilterOutGroups() throws Exception {
+ MailboxACL acl = new MailboxACL(ImmutableMap.of(
+ EntryKey.createGroup("group"), Rfc4314Rights.fromSerializedRfc4314Rights("aet")));
+
+ assertThat(Rights.fromACL(acl))
+ .isEqualTo(Rights.EMPTY);
+ }
+
+ @Test
+ public void fromACLShouldFilterNegatedUsers() throws Exception {
+ MailboxACL acl = new MailboxACL(ImmutableMap.of(
+ EntryKey.createUser("user", NEGATIVE), Rfc4314Rights.fromSerializedRfc4314Rights("aet")));
+
+ assertThat(Rights.fromACL(acl))
+ .isEqualTo(Rights.EMPTY);
+ }
+
+ @Test
+ public void fromACLShouldAcceptUsers() throws Exception {
+ MailboxACL acl = new MailboxACL(ImmutableMap.of(
+ EntryKey.createUser("user"), Rfc4314Rights.fromSerializedRfc4314Rights("aet")));
+
+ assertThat(Rights.fromACL(acl))
+ .isEqualTo(Rights.builder()
+ .delegateTo(new Rights.Username("user"), Rights.Right.Administer, Rights.Right.Expunge, Rights.Right.DeleteMessages)
+ .build());
+ }
+
+ @Test
+ public void fromACLShouldFilterOutUnknownRights() throws Exception {
+ MailboxACL acl = new MailboxACL(ImmutableMap.of(
+ EntryKey.createUser("user"), Rfc4314Rights.fromSerializedRfc4314Rights("aetpk")));
+
+ assertThat(Rights.fromACL(acl))
+ .isEqualTo(Rights.builder()
+ .delegateTo(new Rights.Username("user"), Rights.Right.Administer, Rights.Right.Expunge, Rights.Right.DeleteMessages)
+ .build());
+ }
+
+ @Test
+ public void toMailboxAclShouldReturnEmptyAclWhenEmpty() {
+ Rights rights = Rights.EMPTY;
+
+ assertThat(rights.toMailboxAcl())
+ .isEqualTo(new MailboxACL());
+ }
+
+ @Test
+ public void toMailboxAclShouldReturnAclConversion() throws Exception {
+ String user1 = "user1";
+ String user2 = "user2";
+ Rights rights = Rights.builder()
+ .delegateTo(new Rights.Username(user1), Rights.Right.Administer, Rights.Right.DeleteMessages)
+ .delegateTo(new Rights.Username(user2), Rights.Right.Expunge, Rights.Right.Lookup)
+ .build();
+
+ assertThat(rights.toMailboxAcl())
+ .isEqualTo(new MailboxACL(
+ new Entry(user1, MailboxACL.Right.Administer, MailboxACL.Right.DeleteMessages),
+ new Entry(user2, MailboxACL.Right.PerformExpunge, MailboxACL.Right.Lookup)));
+ }
+
+}
\ 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
[3/6] james-project git commit: JAMES-2162 Allow to update
"sharedWith" JMAP mailbox property
Posted by bt...@apache.org.
JAMES-2162 Allow to update "sharedWith" JMAP mailbox property
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/69d783e6
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/69d783e6
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/69d783e6
Branch: refs/heads/master
Commit: 69d783e6ff1fcf0c8cb863332be0cd215e0c53d4
Parents: 0ac2d41
Author: benwa <bt...@linagora.com>
Authored: Wed Sep 27 17:44:46 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Tue Oct 3 07:52:12 2017 +0700
----------------------------------------------------------------------
.../integration/SetMailboxesMethodTest.java | 478 ++++++++++++++++---
.../james/jmap/json/ObjectMapperFactory.java | 22 +
.../methods/SetMailboxesUpdateProcessor.java | 6 +-
.../model/mailbox/MailboxUpdateRequest.java | 32 +-
.../apache/james/jmap/model/mailbox/Rights.java | 1 -
.../jmap/json/ObjectMapperFactoryTest.java | 57 +++
6 files changed, 519 insertions(+), 77 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/69d783e6/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java
index 87d0c94..cc48707 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMailboxesMethodTest.java
@@ -32,6 +32,7 @@ import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isEmptyOrNullString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
@@ -43,20 +44,23 @@ import org.apache.james.GuiceJamesServer;
import org.apache.james.jmap.DefaultMailboxes;
import org.apache.james.jmap.HttpJmapAuthentication;
import org.apache.james.jmap.api.access.AccessToken;
+import org.apache.james.mailbox.model.MailboxACL.Right;
import org.apache.james.mailbox.model.MailboxConstants;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.probe.MailboxProbe;
import org.apache.james.modules.MailboxProbeImpl;
import org.apache.james.probe.DataProbe;
-import org.apache.james.utils.JmapGuiceProbe;
import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.JmapGuiceProbe;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.http.ContentType;
@@ -65,7 +69,13 @@ public abstract class SetMailboxesMethodTest {
private static final String NAME = "[0][0]";
private static final String ARGUMENTS = "[0][1]";
+ private static final String FIRST_MAILBOX = ARGUMENTS + ".list[0]";
private static final String USERS_DOMAIN = "domain.tld";
+
+ private static final String ADMINISTER = String.valueOf(Right.Administer.asCharacter());
+ private static final String WRITE = String.valueOf(Right.Write.asCharacter());
+ private static final String DELETE_MESSAGES = String.valueOf(Right.DeleteMessages.asCharacter());
+
private static int MAILBOX_NAME_LENGTH_64K = 65536;
protected abstract GuiceJamesServer createJmapServer();
@@ -135,11 +145,11 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
- .when()
+ .when()
.post("/jmap")
- .then()
+ .then()
.statusCode(200)
.body(NAME, equalTo("mailboxesSet"))
.body(ARGUMENTS + ".notCreated", aMapWithSize(1))
@@ -169,7 +179,7 @@ public abstract class SetMailboxesMethodTest {
" ]" +
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -201,7 +211,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -231,7 +241,7 @@ public abstract class SetMailboxesMethodTest {
" ]" +
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -260,7 +270,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -292,7 +302,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap");
@@ -322,7 +332,7 @@ public abstract class SetMailboxesMethodTest {
" ]" +
"]";
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.post("/jmap");
@@ -346,7 +356,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -373,7 +383,7 @@ public abstract class SetMailboxesMethodTest {
"]";
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.post("/jmap");
@@ -395,7 +405,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -422,7 +432,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -444,7 +454,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -472,7 +482,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -500,7 +510,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -527,7 +537,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -554,13 +564,13 @@ public abstract class SetMailboxesMethodTest {
"]";
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.then()
.post("/jmap");
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {}, \"#0\"]]")
.when()
.post("/jmap")
@@ -574,7 +584,7 @@ public abstract class SetMailboxesMethodTest {
public void setMailboxesShouldReturnCreatedMailboxWhenChildOfInboxMailbox() {
String inboxId =
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {}, \"#0\"]]")
.when()
.post("/jmap")
@@ -599,7 +609,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -632,13 +642,13 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap");
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {}, \"#0\"]]")
.when()
.post("/jmap")
@@ -666,7 +676,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -700,7 +710,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -737,7 +747,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -771,7 +781,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -806,7 +816,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -841,7 +851,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -871,7 +881,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -896,7 +906,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -904,7 +914,7 @@ public abstract class SetMailboxesMethodTest {
.statusCode(200);
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {}, \"#0\"]]")
.when()
.post("/jmap")
@@ -928,7 +938,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -958,7 +968,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -986,7 +996,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1018,7 +1028,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1047,7 +1057,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1082,7 +1092,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1113,7 +1123,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1143,7 +1153,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1154,6 +1164,344 @@ public abstract class SetMailboxesMethodTest {
}
@Test
+ public void updateShouldReturnOkWhenClearingSharedWith() {
+ jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ String mailboxId = mailbox.getMailboxId().serialize();
+ String requestBody =
+ "[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]";
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body(requestBody)
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxesSet"))
+ .body(ARGUMENTS + ".updated", contains(mailboxId));
+ }
+
+ @Test
+ public void updateShouldReturnOkWhenSettingNewACL() {
+ jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ String mailboxId = mailbox.getMailboxId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"user\": [\"a\", \"w\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxesSet"))
+ .body(ARGUMENTS + ".updated", contains(mailboxId));
+ }
+
+ @Test
+ public void updateShouldRejectInvalidRights() {
+ jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ String mailboxId = mailbox.getMailboxId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"user\": [\"aw\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .when()
+ .post("/jmap").prettyPeek()
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("error"))
+ .body(ARGUMENTS + ".type", is("invalidArguments"))
+ .body(ARGUMENTS + ".description", containsString("Rights should be represented as single value characters"));
+ }
+
+ @Test
+ public void updateShouldRejectUnhandledRight() {
+ jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ String mailboxId = mailbox.getMailboxId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"user\": [\"p\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("error"))
+ .body(ARGUMENTS + ".type", is("invalidArguments"))
+ .body(ARGUMENTS + ".description", containsString("No matching right for 'p'"));
+ }
+
+ @Test
+ public void updateShouldRejectNonExistingRights() {
+ jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ String mailboxId = mailbox.getMailboxId().serialize();
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"user\": [\"z\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("error"))
+ .body(ARGUMENTS + ".type", is("invalidArguments"))
+ .body(ARGUMENTS + ".description", containsString("No matching right for 'z'"));
+ }
+
+ @Test
+ public void updateShouldApplyWhenSettingNewACL() {
+ String myBox = "myBox";
+ String user = "user";
+ jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, myBox);
+ Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ String mailboxId = mailbox.getMailboxId().serialize();
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"" + user + "\": [\"a\", \"w\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .post("/jmap");
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxes"))
+ .body(FIRST_MAILBOX + ".name", equalTo(myBox))
+ .body(FIRST_MAILBOX + ".sharedWith", hasEntry(user, ImmutableList.of(ADMINISTER, WRITE)));
+ }
+
+ @Test
+ public void updateShouldModifyStoredDataWhenUpdatingACL() {
+ String myBox = "myBox";
+ String user = "user";
+ jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, myBox);
+ Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ String mailboxId = mailbox.getMailboxId().serialize();
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"" + user + "\": [\"a\", \"w\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .post("/jmap");
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"" + user + "\": [\"a\", \"t\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .post("/jmap");
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxes"))
+ .body(FIRST_MAILBOX + ".name", equalTo(myBox))
+ .body(FIRST_MAILBOX + ".sharedWith", hasEntry(user, ImmutableList.of(ADMINISTER, DELETE_MESSAGES)));
+ }
+
+ @Test
+ public void updateShouldClearStoredDataWhenDeleteACL() {
+ String myBox = "myBox";
+ String user = "user";
+ jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, myBox);
+ Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ String mailboxId = mailbox.getMailboxId().serialize();
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"" + user + "\": [\"a\", \"w\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .post("/jmap");
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .post("/jmap");
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxes"))
+ .body(FIRST_MAILBOX + ".name", equalTo(myBox))
+ .body(FIRST_MAILBOX + ".sharedWith", is(ImmutableMap.of()));
+ }
+
+ @Test
+ public void updateShouldModifyStoredDataWhenSwitchingACLUser() {
+ String myBox = "myBox";
+ String user1 = "user1";
+ String user2 = "user2";
+ jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, myBox);
+ Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
+ String mailboxId = mailbox.getMailboxId().serialize();
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"" + user1 + "\": [\"a\", \"w\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .post("/jmap");
+
+ with()
+ .header("Authorization", accessToken.serialize())
+ .body("[" +
+ " [ \"setMailboxes\"," +
+ " {" +
+ " \"update\": {" +
+ " \"" + mailboxId + "\" : {" +
+ " \"sharedWith\" : {\"" + user2 + "\": [\"a\", \"w\"]}" +
+ " }" +
+ " }" +
+ " }," +
+ " \"#0\"" +
+ " ]" +
+ "]")
+ .post("/jmap");
+
+ given()
+ .header("Authorization", accessToken.serialize())
+ .body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
+ .when()
+ .post("/jmap")
+ .then()
+ .statusCode(200)
+ .body(NAME, equalTo("mailboxes"))
+ .body(FIRST_MAILBOX + ".name", equalTo(myBox))
+ .body(FIRST_MAILBOX + ".sharedWith", hasEntry(user2, ImmutableList.of(ADMINISTER, WRITE)));
+ }
+
+ @Test
public void setMailboxesShouldUpdateMailboxNameWhenNameUpdateAskedOnExistingMailbox() {
jmapServer.getProbe(MailboxProbeImpl.class).createMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
Mailbox mailbox = jmapServer.getProbe(MailboxProbeImpl.class).getMailbox(MailboxConstants.USER_NAMESPACE, username, "myBox");
@@ -1173,12 +1521,12 @@ public abstract class SetMailboxesMethodTest {
"]";
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.post("/jmap");
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
.when()
.post("/jmap")
@@ -1214,7 +1562,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1249,12 +1597,12 @@ public abstract class SetMailboxesMethodTest {
"]";
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.post("/jmap");
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
.when()
.post("/jmap")
@@ -1292,7 +1640,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1329,12 +1677,12 @@ public abstract class SetMailboxesMethodTest {
"]";
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.post("/jmap");
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
.when()
.post("/jmap")
@@ -1368,7 +1716,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1401,12 +1749,12 @@ public abstract class SetMailboxesMethodTest {
"]";
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.post("/jmap");
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
.when()
.post("/jmap")
@@ -1445,7 +1793,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1483,12 +1831,12 @@ public abstract class SetMailboxesMethodTest {
"]";
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.post("/jmap");
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
.when()
.post("/jmap")
@@ -1520,7 +1868,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1553,7 +1901,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1595,7 +1943,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1630,7 +1978,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1665,7 +2013,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1698,12 +2046,12 @@ public abstract class SetMailboxesMethodTest {
"]";
with()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.post("/jmap");
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body("[[\"getMailboxes\", {\"ids\": [\"" + mailboxId + "\"]}, \"#0\"]]")
.when()
.post("/jmap")
@@ -1735,7 +2083,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1769,7 +2117,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
@@ -1810,7 +2158,7 @@ public abstract class SetMailboxesMethodTest {
"]";
given()
- .header("Authorization", this.accessToken.serialize())
+ .header("Authorization", accessToken.serialize())
.body(requestBody)
.when()
.post("/jmap")
http://git-wip-us.apache.org/repos/asf/james-project/blob/69d783e6/server/protocols/jmap/src/main/java/org/apache/james/jmap/json/ObjectMapperFactory.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/json/ObjectMapperFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/json/ObjectMapperFactory.java
index 71a1b2b..c48527e 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/json/ObjectMapperFactory.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/json/ObjectMapperFactory.java
@@ -24,6 +24,7 @@ import java.util.Set;
import javax.inject.Inject;
+import org.apache.james.jmap.model.mailbox.Rights;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MessageId;
@@ -43,6 +44,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
public class ObjectMapperFactory {
@@ -66,6 +68,8 @@ public class ObjectMapperFactory {
mailboxIdModule.addSerializer(MessageId.class, new MessageIdSerializer());
mailboxIdModule.addKeyDeserializer(MessageId.class, new MessageIdKeyDeserializer(messageIdFactory));
mailboxIdModule.addKeySerializer(MessageId.class, new MessageIdKeySerializer());
+ mailboxIdModule.addKeyDeserializer(Rights.Username.class, new UsernameKeyDeserializer());
+ mailboxIdModule.addDeserializer(Rights.Right.class, new RightDeserializer());
jacksonModules = JACKSON_BASE_MODULES.add(mailboxIdModule).build();
}
@@ -102,6 +106,24 @@ public class ObjectMapperFactory {
}
}
+ public static class UsernameKeyDeserializer extends KeyDeserializer {
+ @Override
+ public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ return new Rights.Username(key);
+ }
+ }
+
+ public static class RightDeserializer extends JsonDeserializer<Rights.Right> {
+
+ @Override
+ public Rights.Right deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ String nodeValue = p.getValueAsString();
+ Preconditions.checkArgument(nodeValue.length() == 1, "Rights should be represented as single value characters");
+
+ return Rights.Right.forChar(nodeValue.charAt(0));
+ }
+ }
+
public static class MailboxIdKeyDeserializer extends KeyDeserializer {
private MailboxId.Factory factory;
http://git-wip-us.apache.org/repos/asf/james-project/blob/69d783e6/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesUpdateProcessor.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesUpdateProcessor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesUpdateProcessor.java
index 459753c..0e2ad14 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesUpdateProcessor.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMailboxesUpdateProcessor.java
@@ -83,8 +83,7 @@ public class SetMailboxesUpdateProcessor implements SetMailboxesProcessor {
SetMailboxesResponse.Builder responseBuilder = SetMailboxesResponse.builder();
request.getUpdate()
- .entrySet()
- .forEach(update -> handleUpdate(update.getKey(), update.getValue(), responseBuilder, mailboxSession));
+ .forEach((key, value) -> handleUpdate(key, value, responseBuilder, mailboxSession));
timeMetric.stopAndPublish();
return responseBuilder.build();
}
@@ -210,6 +209,9 @@ public class SetMailboxesUpdateProcessor implements SetMailboxesProcessor {
private void updateMailbox(Mailbox mailbox, MailboxUpdateRequest updateRequest, MailboxSession mailboxSession) throws MailboxException {
MailboxPath originMailboxPath = mailboxManager.getMailbox(mailbox.getId(), mailboxSession).getMailboxPath();
MailboxPath destinationMailboxPath = computeNewMailboxPath(mailbox, originMailboxPath, updateRequest, mailboxSession);
+ if (updateRequest.getSharedWith().isPresent()) {
+ mailboxManager.setRights(originMailboxPath, updateRequest.getSharedWith().get().toMailboxAcl(), mailboxSession);
+ }
if (!originMailboxPath.equals(destinationMailboxPath)) {
mailboxManager.renameMailbox(originMailboxPath, destinationMailboxPath, mailboxSession);
http://git-wip-us.apache.org/repos/asf/james-project/blob/69d783e6/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/MailboxUpdateRequest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/MailboxUpdateRequest.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/MailboxUpdateRequest.java
index 65af555..81cfc4a 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/MailboxUpdateRequest.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/MailboxUpdateRequest.java
@@ -46,12 +46,14 @@ public class MailboxUpdateRequest {
private Optional<MailboxId> parentId;
private Optional<Role> role;
private Optional<SortOrder> sortOrder;
+ private Optional<Rights> sharedWith;
private Builder() {
name = Optional.empty();
role = Optional.empty();
sortOrder = Optional.empty();
parentId = Optional.empty();
+ sharedWith = Optional.empty();
}
public Builder name(String name) throws MailboxException {
@@ -80,9 +82,14 @@ public class MailboxUpdateRequest {
throw new NotImplementedException();
}
+ public Builder sharedWith(Rights rights) {
+ Preconditions.checkNotNull(rights);
+ this.sharedWith = Optional.of(rights);
+ return this;
+ }
public MailboxUpdateRequest build() {
- return new MailboxUpdateRequest(name, parentId, role, sortOrder);
+ return new MailboxUpdateRequest(name, parentId, role, sortOrder, sharedWith);
}
}
@@ -90,14 +97,16 @@ public class MailboxUpdateRequest {
private final Optional<MailboxId> parentId;
private final Optional<Role> role;
private final Optional<SortOrder> sortOrder;
+ private final Optional<Rights> sharedWith;
@VisibleForTesting
- MailboxUpdateRequest(Optional<String> name, Optional<MailboxId> parentId, Optional<Role> role, Optional<SortOrder> sortOrder) {
+ MailboxUpdateRequest(Optional<String> name, Optional<MailboxId> parentId, Optional<Role> role, Optional<SortOrder> sortOrder, Optional<Rights> sharedWith) {
this.name = name;
this.parentId = parentId;
this.role = role;
this.sortOrder = sortOrder;
+ this.sharedWith = sharedWith;
}
public Optional<String> getName() {
@@ -116,6 +125,9 @@ public class MailboxUpdateRequest {
return sortOrder;
}
+ public Optional<Rights> getSharedWith() {
+ return sharedWith;
+ }
@Override
public final boolean equals(Object obj) {
@@ -124,23 +136,25 @@ public class MailboxUpdateRequest {
return Objects.equals(this.name, other.name)
&& Objects.equals(this.parentId, other.parentId)
&& Objects.equals(this.role, other.role)
- && Objects.equals(this.sortOrder, other.sortOrder);
+ && Objects.equals(this.sortOrder, other.sortOrder)
+ && Objects.equals(this.sharedWith, other.sharedWith);
}
return false;
}
@Override
public final int hashCode() {
- return Objects.hash(name, parentId, role, sortOrder);
+ return Objects.hash(name, parentId, role, sortOrder, sharedWith);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
- .add("name", name)
- .add("parentId", parentId)
- .add("role", role)
- .add("sortOrder", sortOrder)
- .toString();
+ .add("name", name)
+ .add("parentId", parentId)
+ .add("role", role)
+ .add("sortOrder", sortOrder)
+ .add("sharedWith", sharedWith)
+ .toString();
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/69d783e6/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Rights.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Rights.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Rights.java
index d44e4d3..bd27bd0 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Rights.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Rights.java
@@ -89,7 +89,6 @@ public class Rights {
public static class Username {
private final String value;
- // @JsonCreator
public Username(String value) {
this.value = value;
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/69d783e6/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ObjectMapperFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ObjectMapperFactoryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ObjectMapperFactoryTest.java
index 0985081..9e892fc 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ObjectMapperFactoryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ObjectMapperFactoryTest.java
@@ -19,9 +19,11 @@
package org.apache.james.jmap.json;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.Map;
+import org.apache.james.jmap.model.mailbox.Rights;
import org.apache.james.mailbox.inmemory.InMemoryId;
import org.apache.james.mailbox.inmemory.InMemoryMessageId;
import org.apache.james.mailbox.model.MailboxId;
@@ -72,6 +74,61 @@ public class ObjectMapperFactoryTest {
assertThat(actual).isEqualTo(expectedJson);
}
+ @Test
+ public void readValueShouldParseRightObject() throws Exception {
+ Rights.Right actual = testee.forParsing()
+ .readValue("\"a\"", Rights.Right.class);
+
+ assertThat(actual)
+ .isEqualTo(Rights.Right.Administer);
+ }
+
+ @Test
+ public void readValueShouldParseUsernameObject() throws Exception {
+ String username = "username";
+ Rights.Username actual = testee.forParsing()
+ .readValue("\"" + username + "\"", Rights.Username.class);
+
+ assertThat(actual)
+ .isEqualTo(new Rights.Username(username));
+ }
+
+ @Test
+ public void readValueShouldParseRightsObject() throws Exception {
+ String username = "username";
+ Rights actual = testee.forParsing()
+ .readValue("{\"" + username + "\" : [\"a\", \"e\"]}", Rights.class);
+
+ assertThat(actual)
+ .isEqualTo(Rights.builder()
+ .delegateTo(new Rights.Username(username), Rights.Right.Administer, Rights.Right.Expunge)
+ .build());
+ }
+
+ @Test
+ public void readValueShouldRejectMultiCharacterRights() throws Exception {
+ assertThatThrownBy(() ->
+ testee.forParsing()
+ .readValue("\"ae\"", Rights.Right.class))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void readValueShouldRejectUnsupportedRights() throws Exception {
+ assertThatThrownBy(() ->
+ testee.forParsing()
+ .readValue("\"p\"", Rights.Right.class))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void readValueShouldRejectUnExistingRights() throws Exception {
+ assertThatThrownBy(() ->
+ testee.forParsing()
+ .readValue("\"z\"", Rights.Right.class))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
public static class MailboxIdTestContainer {
public MailboxId mailboxId;
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org