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 rc...@apache.org on 2020/08/26 03:08:19 UTC
[james-project] branch master updated (38de32e -> 7098d70)
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.
from 38de32e JAMES-3187 Update mailing-lists.adoc
new 23fa274 JAMES-3364 DeletedMessageVault: deleting many messages dead-locks
new de174e7 JAMES-3364 DeletedMessageVaultHook: limit Flux flatMap concurrency
new 7098d70 JAMES-3359 Reject Mailbox/set updates when capability is omitted
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../james/vault/DeletedMessageVaultHook.java | 25 +--
.../james/vault/DeletedMessageVaultHookTest.java | 16 ++
.../contract/MailboxSetMethodContract.scala | 184 ++++++++++++++++++++-
.../org/apache/james/jmap/mail/MailboxSet.scala | 61 ++++---
.../james/jmap/method/MailboxSetMethod.scala | 14 +-
5 files changed, 252 insertions(+), 48 deletions(-)
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[james-project] 01/03: JAMES-3364 DeletedMessageVault: deleting
many messages dead-locks
Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 23fa274b00588ada8866836a40b0e6315ca88e24
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Aug 25 15:55:03 2020 +0700
JAMES-3364 DeletedMessageVault: deleting many messages dead-locks
---
.../apache/james/vault/DeletedMessageVaultHook.java | 21 +--------------------
.../james/vault/DeletedMessageVaultHookTest.java | 16 ++++++++++++++++
2 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java
index 72cc971..d357649 100644
--- a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java
+++ b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java
@@ -50,19 +50,6 @@ import reactor.core.publisher.Mono;
public class DeletedMessageVaultHook implements PreDeletionHook {
static class DeletedMessageMailboxContext {
- private static DeletedMessageMailboxContext combine(DeletedMessageMailboxContext first, DeletedMessageMailboxContext second) {
- Preconditions.checkArgument(first.messageId.equals(second.getMessageId()));
- Preconditions.checkArgument(first.owner.equals(second.getOwner()));
-
- return new DeletedMessageMailboxContext(
- first.messageId,
- first.owner,
- ImmutableList.<MailboxId>builder()
- .addAll(first.ownerMailboxes)
- .addAll(second.ownerMailboxes)
- .build());
- }
-
private final MessageId messageId;
private final Username owner;
private final List<MailboxId> ownerMailboxes;
@@ -146,9 +133,7 @@ public class DeletedMessageVaultHook implements PreDeletionHook {
private Flux<DeletedMessageMailboxContext> groupMetadataByOwnerAndMessageId(DeleteOperation deleteOperation) {
return Flux.fromIterable(deleteOperation.getDeletionMetadataList())
.groupBy(MetadataWithMailboxId::getMailboxId)
- .flatMap(this::addOwnerToMetadata)
- .groupBy(this::toMessageIdUserPair)
- .flatMap(groupFlux -> groupFlux.reduce(DeletedMessageMailboxContext::combine));
+ .flatMap(this::addOwnerToMetadata);
}
private Flux<DeletedMessageMailboxContext> addOwnerToMetadata(GroupedFlux<MailboxId, MetadataWithMailboxId> groupedFlux) {
@@ -157,10 +142,6 @@ public class DeletedMessageVaultHook implements PreDeletionHook {
new DeletedMessageMailboxContext(metadata.getMessageMetaData().getMessageId(), owner, ImmutableList.of(metadata.getMailboxId()))));
}
- private Pair<MessageId, Username> toMessageIdUserPair(DeletedMessageMailboxContext deletedMessageMetadata) {
- return Pair.of(deletedMessageMetadata.getMessageId(), deletedMessageMetadata.getOwner());
- }
-
private Mono<Username> retrieveMailboxUser(MailboxId mailboxId) {
return mapperFactory.getMailboxMapper(session)
.findMailboxById(mailboxId)
diff --git a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java
index 688574f..12165b6 100644
--- a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java
+++ b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java
@@ -23,11 +23,13 @@ import static org.apache.james.vault.DeletedMessageFixture.DELETION_DATE;
import static org.apache.james.vault.DeletedMessageFixture.DELIVERY_DATE;
import static org.apache.james.vault.DeletedMessageFixture.INTERNAL_DATE;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.ZoneOffset;
import java.util.List;
+import java.util.stream.IntStream;
import org.apache.james.blob.api.HashBlobId;
import org.apache.james.blob.memory.MemoryDumbBlobStore;
@@ -58,6 +60,7 @@ import org.apache.james.vault.search.Query;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import com.github.fge.lambdas.Throwing;
import com.github.steveash.guavate.Guavate;
import com.google.common.collect.ImmutableList;
@@ -164,6 +167,19 @@ class DeletedMessageVaultHookTest {
}
@Test
+ void deletingManyMessagesShouldSucceed() throws Exception {
+ MailboxId aliceMailbox = mailboxManager.createMailbox(MAILBOX_ALICE_ONE, aliceSession).get();
+ MessageManager messageManager = mailboxManager.getMailbox(aliceMailbox, aliceSession);
+
+ ImmutableList<MessageId> ids = IntStream.range(0, 1000)
+ .mapToObj(Throwing.intFunction(i -> appendMessage(messageManager).getMessageId()))
+ .collect(Guavate.toImmutableList());
+
+ assertThatCode(() -> messageIdManager.delete(ids, aliceSession))
+ .doesNotThrowAnyException();
+ }
+
+ @Test
void notifyDeleteShouldAppendMessageToVaultOfMailboxOwnerWhenOtherUserDeleteMessageInSharingMailbox() throws Exception {
MailboxId aliceMailbox = mailboxManager.createMailbox(MAILBOX_ALICE_ONE, aliceSession).get();
MessageManager aliceMessageManager = mailboxManager.getMailbox(aliceMailbox, aliceSession);
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[james-project] 02/03: JAMES-3364 DeletedMessageVaultHook: limit
Flux flatMap concurrency
Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit de174e7e1172494c735451c76e2c465166423326
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Aug 25 16:57:06 2020 +0700
JAMES-3364 DeletedMessageVaultHook: limit Flux flatMap concurrency
Rely on an hard-coded 8 value (constant).
---
.../main/java/org/apache/james/vault/DeletedMessageVaultHook.java | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java
index d357649..5474f86 100644
--- a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java
+++ b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java
@@ -90,6 +90,8 @@ public class DeletedMessageVaultHook implements PreDeletionHook {
}
}
+ private static final int CONCURRENCY = 8;
+
private final MailboxSession session;
private final DeletedMessageVault deletedMessageVault;
private final DeletedMessageConverter deletedMessageConverter;
@@ -114,7 +116,7 @@ public class DeletedMessageVaultHook implements PreDeletionHook {
Preconditions.checkNotNull(deleteOperation);
return groupMetadataByOwnerAndMessageId(deleteOperation)
- .flatMap(this::appendToTheVault)
+ .flatMap(this::appendToTheVault, CONCURRENCY)
.then();
}
@@ -133,7 +135,7 @@ public class DeletedMessageVaultHook implements PreDeletionHook {
private Flux<DeletedMessageMailboxContext> groupMetadataByOwnerAndMessageId(DeleteOperation deleteOperation) {
return Flux.fromIterable(deleteOperation.getDeletionMetadataList())
.groupBy(MetadataWithMailboxId::getMailboxId)
- .flatMap(this::addOwnerToMetadata);
+ .flatMap(this::addOwnerToMetadata, CONCURRENCY);
}
private Flux<DeletedMessageMailboxContext> addOwnerToMetadata(GroupedFlux<MailboxId, MetadataWithMailboxId> groupedFlux) {
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[james-project] 03/03: JAMES-3359 Reject Mailbox/set updates when
capability is omitted
Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 7098d7071c5debf01d11f37fc757d0c9bcaaa5af
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Aug 25 11:22:52 2020 +0700
JAMES-3359 Reject Mailbox/set updates when capability is omitted
---
.../contract/MailboxSetMethodContract.scala | 184 ++++++++++++++++++++-
.../org/apache/james/jmap/mail/MailboxSet.scala | 61 ++++---
.../james/jmap/method/MailboxSetMethod.scala | 14 +-
3 files changed, 232 insertions(+), 27 deletions(-)
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/MailboxSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
index f968913..2a0fe99 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
@@ -175,7 +175,7 @@ trait MailboxSetMethodContract {
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:quota" ],
| "methodCalls": [
| ["Mailbox/set",
| {
@@ -4476,6 +4476,188 @@ trait MailboxSetMethodContract {
}
@Test
+ def updateRightsResetShouldFailWhenOmittingCapability(server: GuiceJamesServer): Unit = {
+ val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.forUser(BOB, "mailbox"))
+ val request =
+ s"""
+ |{
+ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "update": {
+ | "${mailboxId.serialize()}": {
+ | "/sharedWith": {
+ | "${ANDRE.asString()}":["r", "l"]
+ | }
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}
+ |""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ s"""{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "newState": "000001",
+ | "notUpdated": {
+ | "1": {
+ | "type": "invalidArguments",
+ | "description": "/sharedWith property do not exist thus cannot be updated",
+ | "properties": ["/sharedWith"]
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
+ def updateRightsShouldFailWhenOmittingCapability(server: GuiceJamesServer): Unit = {
+ val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.forUser(BOB, "mailbox"))
+ val request =
+ s"""
+ |{
+ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "update": {
+ | "${mailboxId.serialize()}": {
+ | "/sharedWith/${ANDRE.asString()}": ["r", "l"]
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}
+ |""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ s"""{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "newState": "000001",
+ | "notUpdated": {
+ | "1": {
+ | "type": "invalidArguments",
+ | "description": "/sharedWith/${ANDRE.asString()} property do not exist thus cannot be updated",
+ | "properties": ["/sharedWith/${ANDRE.asString()}"]
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
+ def updateQuotasShouldFailWhenOmittingCapability(server: GuiceJamesServer): Unit = {
+ val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.forUser(BOB, "mailbox"))
+ val request =
+ s"""
+ |{
+ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "update": {
+ | "${mailboxId.serialize()}": {
+ | "/quotas": "toto"
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}
+ |""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ s"""{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "newState": "000001",
+ | "notUpdated": {
+ | "1": {
+ | "type": "invalidArguments",
+ | "description": "/quotas property do not exist thus cannot be updated",
+ | "properties": ["/quotas"]
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
def updateShouldAllowSettingRights(server: GuiceJamesServer): Unit = {
val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.forUser(BOB, "mailbox"))
val request =
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala
index 267fb4d..f3f8db5 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala
@@ -35,8 +35,8 @@ import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.State.State
import org.apache.james.jmap.model.{AccountId, CapabilityIdentifier}
import org.apache.james.mailbox.Role
-import play.api.libs.json.{JsBoolean, JsError, JsNull, JsObject, JsString, JsSuccess, JsValue}
import org.apache.james.mailbox.model.{MailboxId, MailboxACL => JavaMailboxACL}
+import play.api.libs.json.{JsBoolean, JsError, JsNull, JsObject, JsString, JsSuccess, JsValue}
case class MailboxSetRequest(accountId: AccountId,
ifInState: Option[State],
@@ -66,6 +66,13 @@ object MailboxPatchObject {
type KeyConstraint = NonEmpty And StartsWith["/"]
type MailboxPatchObjectKey = String Refined KeyConstraint
+ def notFound(property: String): Either[PatchUpdateValidationException, Update] = {
+ val refinedKey: Either[String, MailboxPatchObjectKey] = refineV(property)
+ refinedKey.fold[Either[PatchUpdateValidationException, Update]](
+ cause => Left(InvalidPropertyException(property = property, cause = s"Invalid property specified in a patch object: $cause")),
+ value => Left(UnsupportedPropertyUpdatedException(value)))
+ }
+
val roleProperty: MailboxPatchObjectKey = "/role"
val sortOrderProperty: MailboxPatchObjectKey = "/sortOrder"
val quotasProperty: MailboxPatchObjectKey = "/quotas"
@@ -79,8 +86,8 @@ object MailboxPatchObject {
}
case class MailboxPatchObject(value: Map[String, JsValue]) {
- def validate(serializer: Serializer): Either[PatchUpdateValidationException, ValidatedMailboxPathObject] = {
- val asUpdatedIterable = updates(serializer)
+ def validate(serializer: Serializer, capabilities: Set[CapabilityIdentifier]): Either[PatchUpdateValidationException, ValidatedMailboxPathObject] = {
+ val asUpdatedIterable = updates(serializer, capabilities)
val maybeParseException: Option[PatchUpdateValidationException] = asUpdatedIterable
.flatMap(x => x match {
@@ -126,13 +133,13 @@ case class MailboxPatchObject(value: Map[String, JsValue]) {
rightsPartialUpdates = partialRightsUpdates)))
}
- private def updates(serializer: Serializer): Iterable[Either[PatchUpdateValidationException, Update]] = value.map({
+ private def updates(serializer: Serializer, capabilities: Set[CapabilityIdentifier]): Iterable[Either[PatchUpdateValidationException, Update]] = value.map({
case (property, newValue) => property match {
case "/name" => NameUpdate.parse(newValue)
- case "/sharedWith" => SharedWithResetUpdate.parse(newValue, serializer)
+ case "/sharedWith" => SharedWithResetUpdate.parse(serializer, capabilities)(newValue)
case "/role" => Left(ServerSetPropertyException(MailboxPatchObject.roleProperty))
case "/sortOrder" => Left(ServerSetPropertyException(MailboxPatchObject.sortOrderProperty))
- case "/quotas" => Left(ServerSetPropertyException(MailboxPatchObject.quotasProperty))
+ case "/quotas" => rejectQuotasUpdate(capabilities)
case "/namespace" => Left(ServerSetPropertyException(MailboxPatchObject.namespaceProperty))
case "/unreadThreads" => Left(ServerSetPropertyException(MailboxPatchObject.unreadThreadsProperty))
case "/totalThreads" => Left(ServerSetPropertyException(MailboxPatchObject.totalThreadsProperty))
@@ -140,14 +147,17 @@ case class MailboxPatchObject(value: Map[String, JsValue]) {
case "/totalEmails" => Left(ServerSetPropertyException(MailboxPatchObject.totalEmailsProperty))
case "/myRights" => Left(ServerSetPropertyException(MailboxPatchObject.myRightsProperty))
case "/isSubscribed" => IsSubscribedUpdate.parse(newValue)
- case property: String if property.startsWith(MailboxPatchObject.sharedWithPrefix) => SharedWithPartialUpdate.parse(newValue, property, serializer)
- case property =>
- val refinedKey: Either[String, MailboxPatchObjectKey] = refineV(property)
- refinedKey.fold[Either[PatchUpdateValidationException, Update]](
- cause => Left(InvalidPropertyException(property = property, cause = s"Invalid property specified in a patch object: $cause")),
- value => Left(UnsupportedPropertyUpdatedException(value)))
+ case property: String if property.startsWith(MailboxPatchObject.sharedWithPrefix) =>
+ SharedWithPartialUpdate.parse(serializer, capabilities)(property, newValue)
+ case property => MailboxPatchObject.notFound(property)
}
})
+
+ private def rejectQuotasUpdate(capabilities: Set[CapabilityIdentifier]) = if (capabilities.contains(CapabilityIdentifier.JAMES_QUOTA)) {
+ Left(ServerSetPropertyException(MailboxPatchObject.quotasProperty))
+ } else {
+ MailboxPatchObject.notFound("/quotas")
+ }
}
case class ValidatedMailboxPathObject(nameUpdate: Option[NameUpdate],
@@ -227,10 +237,16 @@ object NameUpdate {
}
object SharedWithResetUpdate {
- def parse(newValue: JsValue, serializer: Serializer): Either[PatchUpdateValidationException, Update] = serializer.deserializeRights(input = newValue) match {
- case JsSuccess(value, _) => scala.Right(SharedWithResetUpdate(value))
- case JsError(errors) => Left(InvalidUpdateException("/sharedWith", s"Specified value do not match the expected JSON format: $errors"))
- }
+ def parse(serializer: Serializer, capabilities: Set[CapabilityIdentifier])
+ (newValue: JsValue): Either[PatchUpdateValidationException, Update] =
+ if (capabilities.contains(CapabilityIdentifier.JAMES_SHARES)) {
+ serializer.deserializeRights(input = newValue) match {
+ case JsSuccess(value, _) => scala.Right(SharedWithResetUpdate(value))
+ case JsError(errors) => Left(InvalidUpdateException("/sharedWith", s"Specified value do not match the expected JSON format: $errors"))
+ }
+ } else {
+ MailboxPatchObject.notFound("/sharedWith")
+ }
}
object IsSubscribedUpdate {
@@ -242,10 +258,15 @@ object IsSubscribedUpdate {
}
object SharedWithPartialUpdate {
- def parse(newValue: JsValue, property: String, serializer: Serializer): Either[PatchUpdateValidationException, Update] =
- parseUsername(property)
- .flatMap(username => parseRights(newValue, property, serializer)
- .map(rights => SharedWithPartialUpdate(username, rights)))
+ def parse(serializer: Serializer, capabilities: Set[CapabilityIdentifier])
+ ( property: String, newValue: JsValue): Either[PatchUpdateValidationException, Update] =
+ if (capabilities.contains(CapabilityIdentifier.JAMES_SHARES)) {
+ parseUsername(property)
+ .flatMap(username => parseRights(newValue, property, serializer)
+ .map(rights => SharedWithPartialUpdate(username, rights)))
+ } else {
+ MailboxPatchObject.notFound(property)
+ }
def parseUsername(property: String): Either[PatchUpdateValidationException, Username] = try {
scala.Right(Username.of(property.substring(MailboxPatchObject.sharedWithPrefix.length)))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
index 46ad2d7..3613c27 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
@@ -23,7 +23,7 @@ import eu.timepit.refined.auto._
import javax.inject.Inject
import org.apache.james.jmap.json.Serializer
import org.apache.james.jmap.mail.MailboxSetRequest.{MailboxCreationId, UnparsedMailboxId}
-import org.apache.james.jmap.mail.{InvalidPatchException, InvalidPropertyException, InvalidUpdateException, IsSubscribed, IsSubscribedUpdate, MailboxCreationRequest, MailboxCreationResponse, MailboxPatchObject, MailboxRights, MailboxSetError, MailboxSetRequest, MailboxSetResponse, MailboxUpdateResponse, NameUpdate, PatchUpdateValidationException, Properties, RemoveEmailsOnDestroy, ServerSetPropertyException, SetErrorDescription, SharedWithPartialUpdate, SharedWithResetUpdate, SortOrder, [...]
+import org.apache.james.jmap.mail.{InvalidPatchException, InvalidPropertyException, InvalidUpdateException, IsSubscribed, MailboxCreationRequest, MailboxCreationResponse, MailboxPatchObject, MailboxRights, MailboxSetError, MailboxSetRequest, MailboxSetResponse, MailboxUpdateResponse, NameUpdate, Properties, RemoveEmailsOnDestroy, ServerSetPropertyException, SetErrorDescription, SortOrder, TotalEmails, TotalThreads, UnreadEmails, UnreadThreads, UnsupportedPropertyUpdatedException, Validat [...]
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
import org.apache.james.jmap.model.{ClientId, Id, Invocation, ServerId, State}
@@ -148,20 +148,21 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
for {
creationResults <- createMailboxes(mailboxSession, mailboxSetRequest, processingContext)
deletionResults <- deleteMailboxes(mailboxSession, mailboxSetRequest, processingContext)
- updateResults <- updateMailboxes(mailboxSession, mailboxSetRequest, processingContext)
+ updateResults <- updateMailboxes(mailboxSession, mailboxSetRequest, processingContext, capabilities)
} yield createResponse(capabilities, invocation, mailboxSetRequest, creationResults, deletionResults, updateResults)
}))
}
private def updateMailboxes(mailboxSession: MailboxSession,
mailboxSetRequest: MailboxSetRequest,
- processingContext: ProcessingContext): SMono[UpdateResults] = {
+ processingContext: ProcessingContext,
+ capabilities: Set[CapabilityIdentifier]): SMono[UpdateResults] = {
SFlux.fromIterable(mailboxSetRequest.update.getOrElse(Seq()))
.flatMap({
case (unparsedMailboxId: UnparsedMailboxId, patch: MailboxPatchObject) =>
processingContext.resolveMailboxId(unparsedMailboxId, mailboxIdFactory).fold(
e => SMono.just(UpdateFailure(unparsedMailboxId, e)),
- mailboxId => updateMailbox(mailboxSession, mailboxId, patch))
+ mailboxId => updateMailbox(mailboxSession, mailboxId, patch, capabilities))
.onErrorResume(e => SMono.just(UpdateFailure(unparsedMailboxId, e)))
})
.collectSeq()
@@ -170,8 +171,9 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
private def updateMailbox(mailboxSession: MailboxSession,
mailboxId: MailboxId,
- patch: MailboxPatchObject): SMono[UpdateResult] = {
- patch.validate(serializer)
+ patch: MailboxPatchObject,
+ capabilities: Set[CapabilityIdentifier]): SMono[UpdateResult] = {
+ patch.validate(serializer, capabilities)
.fold(e => SMono.raiseError(e), validatedPatch =>
updateMailboxPath(mailboxId, validatedPatch, mailboxSession)
.`then`(updateMailboxRights(mailboxId, validatedPatch, mailboxSession))
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org