You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2020/12/21 07:29:40 UTC
[james-project] 15/17: JAMES-3481 Add capability for fetching
delegated change
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 7bf36b33bfee86afb56eade0ffbc57b3d931cb2e
Author: LanKhuat <dl...@linagora.com>
AuthorDate: Wed Dec 16 18:15:25 2020 +0700
JAMES-3481 Add capability for fetching delegated change
---
.../change/CassandraMailboxChangeRepository.java | 8 ++-
.../jmap/api/change/MailboxChangeRepository.java | 2 +
.../change/MemoryMailboxChangeRepository.java | 20 ++++++
.../change/MailboxChangeRepositoryContract.java | 2 +-
.../contract/MailboxChangesMethodContract.scala | 83 ++++++++++++++++++++--
.../james/jmap/method/MailboxChangesMethod.scala | 9 ++-
6 files changed, 114 insertions(+), 10 deletions(-)
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java
index 738d9c2..72410b6 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java
@@ -22,6 +22,7 @@ package org.apache.james.jmap.cassandra.change;
import java.util.Optional;
import org.apache.james.jmap.api.change.MailboxChange;
+import org.apache.james.jmap.api.change.MailboxChange.Limit;
import org.apache.james.jmap.api.change.MailboxChangeRepository;
import org.apache.james.jmap.api.change.MailboxChanges;
import org.apache.james.jmap.api.model.AccountId;
@@ -36,7 +37,12 @@ public class CassandraMailboxChangeRepository implements MailboxChangeRepository
}
@Override
- public Mono<MailboxChanges> getSinceState(AccountId accountId, MailboxChange.State state, Optional<MailboxChange.Limit> maxIdsToReturn) {
+ public Mono<MailboxChanges> getSinceState(AccountId accountId, MailboxChange.State state, Optional<Limit> maxChanges) {
+ return Mono.empty();
+ }
+
+ @Override
+ public Mono<MailboxChanges> getSinceStateWithDelegation(AccountId accountId, MailboxChange.State state, Optional<Limit> maxChanges) {
return Mono.empty();
}
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChangeRepository.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChangeRepository.java
index 006316b..201e022 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChangeRepository.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChangeRepository.java
@@ -33,5 +33,7 @@ public interface MailboxChangeRepository {
Mono<MailboxChanges> getSinceState(AccountId accountId, State state, Optional<Limit> maxChanges);
+ Mono<MailboxChanges> getSinceStateWithDelegation(AccountId accountId, State state, Optional<Limit> maxChanges);
+
Mono<State> getLatestState(AccountId accountId);
}
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java
index 5dad517..ab91994 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java
@@ -21,6 +21,7 @@ package org.apache.james.jmap.memory.change;
import java.util.Comparator;
import java.util.Optional;
+import java.util.function.Predicate;
import org.apache.james.jmap.api.change.MailboxChange;
import org.apache.james.jmap.api.change.MailboxChange.Limit;
@@ -69,6 +70,25 @@ public class MemoryMailboxChangeRepository implements MailboxChangeRepository {
return findByState(accountId, state)
.flatMapMany(currentState -> Flux.fromIterable(mailboxChangeMap.get(accountId))
.filter(change -> change.getDate().isAfter(currentState.getDate()))
+ .filter(Predicate.not(MailboxChange::isDelegated))
+ .sort(Comparator.comparing(MailboxChange::getDate)))
+ .collect(new MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+ }
+
+ @Override
+ public Mono<MailboxChanges> getSinceStateWithDelegation(AccountId accountId, State state, Optional<Limit> maxChanges) {
+ Preconditions.checkNotNull(accountId);
+ Preconditions.checkNotNull(state);
+ maxChanges.ifPresent(limit -> Preconditions.checkArgument(limit.getValue() > 0, "maxChanges must be a positive integer"));
+ if (state.equals(State.INITIAL)) {
+ return Flux.fromIterable(mailboxChangeMap.get(accountId))
+ .sort(Comparator.comparing(MailboxChange::getDate))
+ .collect(new MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+ }
+
+ return findByState(accountId, state)
+ .flatMapMany(currentState -> Flux.fromIterable(mailboxChangeMap.get(accountId))
+ .filter(change -> change.getDate().isAfter(currentState.getDate()))
.sort(Comparator.comparing(MailboxChange::getDate)))
.collect(new MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
}
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
index 26c04ba..293d448 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
@@ -351,7 +351,7 @@ public interface MailboxChangeRepositoryContract {
repository.save(oldState);
repository.save(change1);
- assertThat(repository.getSinceState(ACCOUNT_ID, STATE_0, Optional.empty()).block().getUpdated())
+ assertThat(repository.getSinceStateWithDelegation(ACCOUNT_ID, STATE_0, Optional.empty()).block().getUpdated())
.containsExactly(TestId.of(1));
}
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala
index e07eef1..4467a54 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxChangesMethodContract.scala
@@ -489,7 +489,7 @@ trait MailboxChangesMethodContract {
val request =
s"""{
- | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares"],
| "methodCalls": [[
| "Mailbox/changes",
| {
@@ -553,7 +553,7 @@ trait MailboxChangesMethodContract {
val request =
s"""{
- | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares"],
| "methodCalls": [[
| "Mailbox/changes",
| {
@@ -624,7 +624,7 @@ trait MailboxChangesMethodContract {
val request =
s"""{
- | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares"],
| "methodCalls": [[
| "Mailbox/changes",
| {
@@ -694,7 +694,7 @@ trait MailboxChangesMethodContract {
val request =
s"""{
- | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares"],
| "methodCalls": [[
| "Mailbox/changes",
| {
@@ -765,7 +765,7 @@ trait MailboxChangesMethodContract {
val request =
s"""{
- | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares"],
| "methodCalls": [[
| "Mailbox/changes",
| {
@@ -810,6 +810,77 @@ trait MailboxChangesMethodContract {
}
@Test
+ def mailboxChangesShouldNotReturnUpdatedChangesWhenMissingSharesCapability(server: GuiceJamesServer): Unit = {
+ val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+
+ provisionSystemMailboxes(server)
+
+ val path = MailboxPath.forUser(BOB, "mailbox1")
+ val mailboxId: String = mailboxProbe
+ .createMailbox(path)
+ .serialize
+
+ server.getProbe(classOf[ACLProbeImpl])
+ .replaceRights(path, ANDRE.asString, new MailboxACL.Rfc4314Rights(Right.Lookup, Right.Read))
+
+ val message: Message = Message.Builder
+ .of
+ .setSubject("test")
+ .setBody("testmail", StandardCharsets.UTF_8)
+ .build
+ val messageId: MessageId = mailboxProbe.appendMessage(BOB.asString(), path, AppendCommand.from(message)).getMessageId
+
+ val oldState: State = storeReferenceState(server, ANDRE)
+
+ destroyEmail(messageId)
+
+ val request =
+ s"""{
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [[
+ | "Mailbox/changes",
+ | {
+ | "accountId": "$ANDRE_ACCOUNT_ID",
+ | "sinceState": "${oldState.getValue}"
+ | },
+ | "c1"]]
+ |}""".stripMargin
+
+ val response = `given`(
+ baseRequestSpecBuilder(server)
+ .setAuth(authScheme(UserCredential(ANDRE, ANDRE_PASSWORD)))
+ .addHeader(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .setBody(request)
+ .build, new ResponseSpecBuilder().build)
+ .post
+ .`then`
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response)
+ .whenIgnoringPaths("methodResponses[0][1].newState")
+ .withOptions(new Options(IGNORING_ARRAY_ORDER))
+ .isEqualTo(
+ s"""{
+ | "sessionState": "${SESSION_STATE.value}",
+ | "methodResponses": [
+ | [ "Mailbox/changes", {
+ | "accountId": "$ANDRE_ACCOUNT_ID",
+ | "oldState": "${oldState.getValue}",
+ | "hasMoreChanges": false,
+ | "updatedProperties": [],
+ | "created": [],
+ | "updated": [],
+ | "destroyed": []
+ | }, "c1"]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
@Disabled("Not implemented yet")
def mailboxChangesShouldReturnUpdatedChangesWhenDestroyDelegatedMailbox(server: GuiceJamesServer): Unit = {
val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
@@ -830,7 +901,7 @@ trait MailboxChangesMethodContract {
val request =
s"""{
- | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail", "urn:apache:james:params:jmap:mail:shares"],
| "methodCalls": [[
| "Mailbox/changes",
| {
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala
index 8daac10..5bbca81 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala
@@ -26,7 +26,7 @@ import org.apache.james.jmap.api.change.MailboxChangeRepository
import org.apache.james.jmap.api.model.{AccountId => JavaAccountId}
import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, JMAP_MAIL}
import org.apache.james.jmap.core.Invocation.{Arguments, MethodName}
-import org.apache.james.jmap.core.{Invocation, Properties, State}
+import org.apache.james.jmap.core.{CapabilityIdentifier, Invocation, Properties, State}
import org.apache.james.jmap.json.{MailboxSerializer, ResponseSerializer}
import org.apache.james.jmap.mail.{HasMoreChanges, MailboxChangesRequest, MailboxChangesResponse}
import org.apache.james.jmap.routes.SessionSupplier
@@ -46,7 +46,12 @@ class MailboxChangesMethod @Inject()(mailboxSerializer: MailboxSerializer,
override val requiredCapabilities: Set[CapabilityIdentifier] = Set(JMAP_MAIL)
override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: MailboxChangesRequest): SMono[InvocationWithContext] =
- SMono.fromPublisher(mailboxChangeRepository.getSinceState(JavaAccountId.fromUsername(mailboxSession.getUser), JavaState.of(request.sinceState.value), request.maxChanged.toJava))
+ SMono.fromPublisher(
+ if (capabilities.contains(CapabilityIdentifier.JAMES_SHARES)) {
+ mailboxChangeRepository.getSinceStateWithDelegation(JavaAccountId.fromUsername(mailboxSession.getUser), JavaState.of(request.sinceState.value), request.maxChanged.toJava)
+ } else {
+ mailboxChangeRepository.getSinceState(JavaAccountId.fromUsername(mailboxSession.getUser), JavaState.of(request.sinceState.value), request.maxChanged.toJava)
+ })
.map(mailboxChanges => MailboxChangesResponse(
accountId = request.accountId,
oldState = request.sinceState,
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org