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 80180aa166b93d7df3ec2ec868a617c79b5f8c66
Author: Tung Van TRAN <[email protected]>
AuthorDate: Thu Oct 13 08:23:36 2022 +0700

    JAMES-3830 Quota extension and shared mailboxes
---
 .../store/quota/DefaultUserQuotaRootResolver.java  |   3 +-
 .../rfc8621/contract/QuotaGetMethodContract.scala  | 316 ++++++++++++++++++++-
 .../scala/org/apache/james/jmap/mail/Quotas.scala  |  14 +-
 .../apache/james/jmap/method/QuotaGetMethod.scala  |  37 ++-
 4 files changed, 336 insertions(+), 34 deletions(-)

diff --git 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/DefaultUserQuotaRootResolver.java
 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/DefaultUserQuotaRootResolver.java
index df23ba4bfb..00506ca094 100644
--- 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/DefaultUserQuotaRootResolver.java
+++ 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/DefaultUserQuotaRootResolver.java
@@ -38,6 +38,7 @@ import org.apache.james.mailbox.model.search.MailboxQuery;
 import org.apache.james.mailbox.quota.QuotaRootDeserializer;
 import org.apache.james.mailbox.quota.UserQuotaRootResolver;
 import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
+import org.apache.james.util.ReactorUtils;
 import org.reactivestreams.Publisher;
 
 import com.google.common.base.Preconditions;
@@ -134,7 +135,7 @@ public class DefaultUserQuotaRootResolver implements 
UserQuotaRootResolver {
 
         Flux<QuotaRoot> quotaRootListFromDelegatedMailboxes = 
factory.getMailboxMapper(session)
             .findNonPersonalMailboxes(username, MailboxACL.Right.Read)
-            .flatMap(this::getQuotaRootReactive)
+            .flatMap(this::getQuotaRootReactive, 
ReactorUtils.DEFAULT_CONCURRENCY)
             .distinct();
 
         return Flux.concat(quotaRootListFromDelegatedMailboxes, 
Flux.just(forUser(username)));
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/QuotaGetMethodContract.scala
 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/QuotaGetMethodContract.scala
index ed3f742667..f99b6d6b17 100644
--- 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/QuotaGetMethodContract.scala
+++ 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/QuotaGetMethodContract.scala
@@ -32,14 +32,15 @@ import org.apache.james.jmap.http.UserCredential
 import org.apache.james.jmap.mail.{CountResourceType, QuotaIdFactory}
 import 
org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, 
ANDRE, ANDRE_PASSWORD, BOB, BOB_PASSWORD, DOMAIN, authScheme, 
baseRequestSpecBuilder}
 import org.apache.james.mailbox.MessageManager.AppendCommand
-import org.apache.james.mailbox.model.MailboxPath
+import org.apache.james.mailbox.model.{MailboxACL, MailboxPath}
 import org.apache.james.mime4j.dom.Message
-import org.apache.james.modules.{MailboxProbeImpl, QuotaProbesImpl}
+import org.apache.james.modules.{ACLProbeImpl, MailboxProbeImpl, 
QuotaProbesImpl}
 import org.apache.james.utils.DataProbeImpl
 import org.junit.jupiter.api.{BeforeEach, Test}
 
 import java.nio.charset.StandardCharsets
-
+import org.apache.james.mailbox.model.MailboxACL.Right.Read
+import org.apache.james.mailbox.model.MailboxACL.Right.Lookup
 
 trait QuotaGetMethodContract {
 
@@ -140,7 +141,7 @@ trait QuotaGetMethodContract {
          |                "list": [
          |                    {
          |                        "used": 0,
-         |                        "name": "account:count:Mail",
+         |                        "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
          |                        "id": 
"08417be420b6dd6fa77d48fb2438e0d19108cd29424844bb109b52d356fab528",
          |                        "dataTypes": [
          |                            "Mail"
@@ -152,7 +153,7 @@ trait QuotaGetMethodContract {
          |                    },
          |                    {
          |                        "used": 0,
-         |                        "name": "account:octets:Mail",
+         |                        "name": 
"#private&[email protected]@domain.tld:account:octets:Mail",
          |                        "id": 
"eab6ce8ac5d9730a959e614854410cf39df98ff3760a623b8e540f36f5184947",
          |                        "dataTypes": [
          |                            "Mail"
@@ -312,7 +313,7 @@ trait QuotaGetMethodContract {
          |                "list": [
          |                    {
          |                        "used": 0,
-         |                        "name": "account:count:Mail",
+         |                        "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
          |                        "id": 
"08417be420b6dd6fa77d48fb2438e0d19108cd29424844bb109b52d356fab528",
          |                        "dataTypes": [
          |                            "Mail"
@@ -383,7 +384,7 @@ trait QuotaGetMethodContract {
          |                "list": [
          |                    {
          |                        "used": 1,
-         |                        "name": "account:count:Mail",
+         |                        "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
          |                        "id": 
"08417be420b6dd6fa77d48fb2438e0d19108cd29424844bb109b52d356fab528",
          |                        "dataTypes": [
          |                            "Mail"
@@ -395,7 +396,7 @@ trait QuotaGetMethodContract {
          |                    },
          |                    {
          |                        "used": 85,
-         |                        "name": "account:octets:Mail",
+         |                        "name": 
"#private&[email protected]@domain.tld:account:octets:Mail",
          |                        "id": 
"eab6ce8ac5d9730a959e614854410cf39df98ff3760a623b8e540f36f5184947",
          |                        "dataTypes": [
          |                            "Mail"
@@ -714,7 +715,7 @@ trait QuotaGetMethodContract {
          |        {
          |          "id": 
"08417be420b6dd6fa77d48fb2438e0d19108cd29424844bb109b52d356fab528",
          |          "used": 0,
-         |          "name": "account:count:Mail",
+         |          "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
          |          "limit": 100
          |        }
          |      ],
@@ -873,7 +874,7 @@ trait QuotaGetMethodContract {
          |                "list": [
          |                    {
          |                        "used": 1,
-         |                        "name": "account:count:Mail",
+         |                        "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
          |                        "id": 
"08417be420b6dd6fa77d48fb2438e0d19108cd29424844bb109b52d356fab528",
          |                        "dataTypes": [
          |                            "Mail"
@@ -885,7 +886,7 @@ trait QuotaGetMethodContract {
          |                    },
          |                    {
          |                        "used": 85,
-         |                        "name": "account:octets:Mail",
+         |                        "name": 
"#private&[email protected]@domain.tld:account:octets:Mail",
          |                        "id": 
"eab6ce8ac5d9730a959e614854410cf39df98ff3760a623b8e540f36f5184947",
          |                        "dataTypes": [
          |                            "Mail"
@@ -903,4 +904,297 @@ trait QuotaGetMethodContract {
          |}
          |""".stripMargin)
   }
+
+  @Test
+  def 
quotaGetShouldNotReturnQuotaRootOfDelegatedMailboxWhenNotExtension(server: 
GuiceJamesServer): Unit = {
+    val quotaProbe = server.getProbe(classOf[QuotaProbesImpl])
+    val bobQuotaRoot = quotaProbe.getQuotaRoot(MailboxPath.inbox(BOB))
+    quotaProbe.setMaxMessageCount(bobQuotaRoot, QuotaCountLimit.count(100L))
+
+    // setup delegated Mailbox
+    val andreMailbox = MailboxPath.forUser(ANDRE, "mailbox")
+    val mailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(andreMailbox)
+    server.getProbe(classOf[ACLProbeImpl])
+      .replaceRights(andreMailbox, BOB.asString, new 
MailboxACL.Rfc4314Rights(Read))
+
+    quotaProbe.setMaxMessageCount(quotaProbe.getQuotaRoot(andreMailbox), 
QuotaCountLimit.count(88L))
+
+
+    val response = `given`
+      .body(
+        s"""{
+           |  "using": [
+           |    "urn:ietf:params:jmap:core",
+           |    "urn:ietf:params:jmap:quota"],
+           |  "methodCalls": [[
+           |    "Quota/get",
+           |    {
+           |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |      "ids": null
+           |    },
+           |    "c1"]]
+           |}""".stripMargin)
+  .when
+      .post
+  .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response).isEqualTo(
+      s"""{
+         |    "sessionState": "${SESSION_STATE.value}",
+         |    "methodResponses": [
+         |        [
+         |            "Quota/get",
+         |            {
+         |                "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |                "notFound": [],
+         |                "state": "${INSTANCE.value}",
+         |                "list": [
+         |                    {
+         |                        "used": 0,
+         |                        "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
+         |                        "id": 
"08417be420b6dd6fa77d48fb2438e0d19108cd29424844bb109b52d356fab528",
+         |                        "dataTypes": [
+         |                            "Mail"
+         |                        ],
+         |                        "limit": 100,
+         |                        "warnLimit": 90,
+         |                        "resourceType": "count",
+         |                        "scope": "account"
+         |                    }
+         |                ]
+         |            },
+         |            "c1"
+         |        ]
+         |    ]
+         |}
+         |""".stripMargin)
+  }
+
+  @Test
+  def quotaGetShouldReturnQuotaRootOfDelegatedMailboxWhenExtension(server: 
GuiceJamesServer): Unit = {
+    val quotaProbe = server.getProbe(classOf[QuotaProbesImpl])
+    val bobQuotaRoot = quotaProbe.getQuotaRoot(MailboxPath.inbox(BOB))
+    quotaProbe.setMaxMessageCount(bobQuotaRoot, QuotaCountLimit.count(100L))
+
+    // setup delegated Mailbox
+    val andreMailbox = MailboxPath.forUser(ANDRE, "mailbox")
+    val mailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(andreMailbox)
+    server.getProbe(classOf[ACLProbeImpl])
+      .replaceRights(andreMailbox, BOB.asString, new 
MailboxACL.Rfc4314Rights(Read))
+
+    quotaProbe.setMaxMessageCount(quotaProbe.getQuotaRoot(andreMailbox), 
QuotaCountLimit.count(88L))
+
+    val response = `given`
+      .body(
+        s"""{
+           |  "using": [
+           |    "urn:ietf:params:jmap:core",
+           |    "urn:ietf:params:jmap:quota",
+           |    "urn:apache:james:params:jmap:mail:shares" ],
+           |  "methodCalls": [[
+           |    "Quota/get",
+           |    {
+           |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |      "ids": null
+           |    },
+           |    "c1"]]
+           |}""".stripMargin)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response).isEqualTo(
+      s"""{
+         |    "sessionState": "${SESSION_STATE.value}",
+         |    "methodResponses": [
+         |        [
+         |            "Quota/get",
+         |            {
+         |                "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |                "notFound": [],
+         |                "state": "${INSTANCE.value}",
+         |                "list": [
+         |                    {
+         |                        "used": 0,
+         |                        "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
+         |                        "id": 
"08417be420b6dd6fa77d48fb2438e0d19108cd29424844bb109b52d356fab528",
+         |                        "dataTypes": [
+         |                            "Mail"
+         |                        ],
+         |                        "limit": 100,
+         |                        "warnLimit": 90,
+         |                        "resourceType": "count",
+         |                        "scope": "account"
+         |                    },
+         |                    {
+         |                        "used": 0,
+         |                        "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
+         |                        "warnLimit": 79,
+         |                        "id": 
"04cbe4578878e02a74e47ae6be66c88cc8aafd3a5fc698457d712ee5f9a5b4ca",
+         |                        "dataTypes": [
+         |                            "Mail"
+         |                        ],
+         |                        "limit": 88,
+         |                        "resourceType": "count",
+         |                        "scope": "account"
+         |                    }
+         |                ]
+         |            },
+         |            "c1"
+         |        ]
+         |    ]
+         |}
+         |""".stripMargin)
+  }
+
+  @Test
+  def 
quotaGetShouldReturnQuotaRootOfDelegatedMailboxWhenNotHasReadRight(server: 
GuiceJamesServer): Unit = {
+    val quotaProbe = server.getProbe(classOf[QuotaProbesImpl])
+    val bobQuotaRoot = quotaProbe.getQuotaRoot(MailboxPath.inbox(BOB))
+    quotaProbe.setMaxMessageCount(bobQuotaRoot, QuotaCountLimit.count(100L))
+
+    // setup delegated Mailbox
+    val andreMailbox = MailboxPath.forUser(ANDRE, "mailbox")
+    val mailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(andreMailbox)
+    server.getProbe(classOf[ACLProbeImpl])
+      .replaceRights(andreMailbox, BOB.asString, new 
MailboxACL.Rfc4314Rights(Lookup))
+
+    quotaProbe.setMaxMessageCount(quotaProbe.getQuotaRoot(andreMailbox), 
QuotaCountLimit.count(88L))
+
+    val response = `given`
+      .body(
+        s"""{
+           |  "using": [
+           |    "urn:ietf:params:jmap:core",
+           |    "urn:ietf:params:jmap:quota",
+           |    "urn:apache:james:params:jmap:mail:shares" ],
+           |  "methodCalls": [[
+           |    "Quota/get",
+           |    {
+           |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |      "ids": null
+           |    },
+           |    "c1"]]
+           |}""".stripMargin)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response).isEqualTo(
+      s"""{
+         |    "sessionState": "${SESSION_STATE.value}",
+         |    "methodResponses": [
+         |        [
+         |            "Quota/get",
+         |            {
+         |                "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |                "notFound": [],
+         |                "state": "${INSTANCE.value}",
+         |                "list": [
+         |                    {
+         |                        "used": 0,
+         |                        "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
+         |                        "id": 
"08417be420b6dd6fa77d48fb2438e0d19108cd29424844bb109b52d356fab528",
+         |                        "dataTypes": [
+         |                            "Mail"
+         |                        ],
+         |                        "limit": 100,
+         |                        "warnLimit": 90,
+         |                        "resourceType": "count",
+         |                        "scope": "account"
+         |                    }
+         |                ]
+         |            },
+         |            "c1"
+         |        ]
+         |    ]
+         |}
+         |""".stripMargin)
+  }
+
+  @Test
+  def 
quotaGetShouldReturnQuotaRootOfDelegatedMailboxWhenProvideCorrectId(server: 
GuiceJamesServer): Unit = {
+    val quotaProbe = server.getProbe(classOf[QuotaProbesImpl])
+    val bobQuotaRoot = quotaProbe.getQuotaRoot(MailboxPath.inbox(BOB))
+    quotaProbe.setMaxMessageCount(bobQuotaRoot, QuotaCountLimit.count(100L))
+
+    // setup delegated Mailbox
+    val andreMailbox = MailboxPath.forUser(ANDRE, "mailbox")
+    val mailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(andreMailbox)
+    server.getProbe(classOf[ACLProbeImpl])
+      .replaceRights(andreMailbox, BOB.asString, new 
MailboxACL.Rfc4314Rights(Read))
+
+    quotaProbe.setMaxMessageCount(quotaProbe.getQuotaRoot(andreMailbox), 
QuotaCountLimit.count(88L))
+
+    val response = `given`
+      .body(
+        s"""{
+           |  "using": [
+           |    "urn:ietf:params:jmap:core",
+           |    "urn:ietf:params:jmap:quota",
+           |    "urn:apache:james:params:jmap:mail:shares" ],
+           |  "methodCalls": [[
+           |    "Quota/get",
+           |    {
+           |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |      "ids": 
["04cbe4578878e02a74e47ae6be66c88cc8aafd3a5fc698457d712ee5f9a5b4ca"]
+           |    },
+           |    "c1"]]
+           |}""".stripMargin)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response).isEqualTo(
+      s"""{
+         |    "sessionState": "${SESSION_STATE.value}",
+         |    "methodResponses": [
+         |        [
+         |            "Quota/get",
+         |            {
+         |                "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |                "notFound": [],
+         |                "state": "${INSTANCE.value}",
+         |                "list": [
+         |                    {
+         |                        "used": 0,
+         |                        "name": 
"#private&[email protected]@domain.tld:account:count:Mail",
+         |                        "warnLimit": 79,
+         |                        "id": 
"04cbe4578878e02a74e47ae6be66c88cc8aafd3a5fc698457d712ee5f9a5b4ca",
+         |                        "dataTypes": [
+         |                            "Mail"
+         |                        ],
+         |                        "limit": 88,
+         |                        "resourceType": "count",
+         |                        "scope": "account"
+         |                    }
+         |                ]
+         |            },
+         |            "c1"
+         |        ]
+         |    ]
+         |}
+         |""".stripMargin)
+  }
+
 }
diff --git 
a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Quotas.scala
 
b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Quotas.scala
index 938a6612e1..1c4545a5d9 100644
--- 
a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Quotas.scala
+++ 
b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Quotas.scala
@@ -84,9 +84,9 @@ object JmapQuota {
   val allProperties: Properties = Properties("id", "resourceType", "used", 
"limit", "scope", "name", "dataTypes", "warnLimit", "softLimit", "description")
   val idProperty: Properties = Properties("id")
 
-  def propertiesFiltered(requestedProperties: Properties) : Properties = 
idProperty ++ requestedProperties
+  def propertiesFiltered(requestedProperties: Properties): Properties = 
idProperty ++ requestedProperties
 
-  def extractUserMessageCountQuota(quota: ModelQuota[QuotaCountLimit, 
QuotaCountUsage], countQuotaIdPlaceHolder: Id): Option[JmapQuota] =
+  def extractUserMessageCountQuota(quota: ModelQuota[QuotaCountLimit, 
QuotaCountUsage], countQuotaIdPlaceHolder: Id, quotaRoot: ModelQuotaRoot): 
Option[JmapQuota] =
     Option(quota.getLimitByScope.get(ModelQuota.Scope.User))
       .map(limit => JmapQuota(
         id = countQuotaIdPlaceHolder,
@@ -94,11 +94,11 @@ object JmapQuota {
         used = UnsignedInt.liftOrThrow(quota.getUsed.asLong()),
         limit = UnsignedInt.liftOrThrow(limit.asLong()),
         scope = AccountScope,
-        name = QuotaName.from(AccountScope, CountResourceType, 
List(MailDataType)),
+        name = QuotaName.from(quotaRoot, AccountScope, CountResourceType, 
List(MailDataType)),
         dataTypes = List(MailDataType),
         warnLimit = Some(UnsignedInt.liftOrThrow((limit.asLong() * 
WARN_LIMIT_PERCENTAGE).toLong))))
 
-  def extractUserMessageSizeQuota(quota: ModelQuota[QuotaSizeLimit, 
QuotaSizeUsage], sizeQuotaIdPlaceHolder: Id): Option[JmapQuota] =
+  def extractUserMessageSizeQuota(quota: ModelQuota[QuotaSizeLimit, 
QuotaSizeUsage], sizeQuotaIdPlaceHolder: Id, quotaRoot: ModelQuotaRoot): 
Option[JmapQuota] =
     Option(quota.getLimitByScope.get(ModelQuota.Scope.User))
       .map(limit => JmapQuota(
         id = sizeQuotaIdPlaceHolder,
@@ -106,7 +106,7 @@ object JmapQuota {
         used = UnsignedInt.liftOrThrow(quota.getUsed.asLong()),
         limit = UnsignedInt.liftOrThrow(limit.asLong()),
         scope = AccountScope,
-        name = QuotaName.from(AccountScope, OctetsResourceType, 
List(MailDataType)),
+        name = QuotaName.from(quotaRoot, AccountScope, OctetsResourceType, 
List(MailDataType)),
         dataTypes = List(MailDataType),
         warnLimit = Some(UnsignedInt.liftOrThrow((limit.asLong() * 
WARN_LIMIT_PERCENTAGE).toLong))))
 }
@@ -123,8 +123,8 @@ case class JmapQuota(id: Id,
                      description: Option[QuotaDescription] = None)
 
 object QuotaName {
-  def from(scope: Scope, resourceType: ResourceType, dataTypes: 
List[DataType]): QuotaName =
-    
QuotaName(s"${scope.asString()}:${resourceType.asString()}:${dataTypes.map(_.asString()).mkString("_")}")
+  def from(quotaRoot: ModelQuotaRoot, scope: Scope, resourceType: 
ResourceType, dataTypes: List[DataType]): QuotaName =
+    
QuotaName(s"${quotaRoot.asString()}:${scope.asString()}:${resourceType.asString()}:${dataTypes.map(_.asString()).mkString("_")}")
 }
 
 case class QuotaName(string: String)
diff --git 
a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/QuotaGetMethod.scala
 
b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/QuotaGetMethod.scala
index 73dc94ade1..3cd6c519f4 100644
--- 
a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/QuotaGetMethod.scala
+++ 
b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/QuotaGetMethod.scala
@@ -21,7 +21,7 @@ package org.apache.james.jmap.method
 
 import eu.timepit.refined.auto._
 import org.apache.james.core.Username
-import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, 
JMAP_CORE, JMAP_QUOTA}
+import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, 
JAMES_SHARES, JMAP_CORE, JMAP_QUOTA}
 import org.apache.james.jmap.core.Invocation.{Arguments, MethodCallId, 
MethodName}
 import org.apache.james.jmap.core.{ErrorCode, Invocation, 
MissingCapabilityException, Properties}
 import org.apache.james.jmap.json.{QuotaSerializer, ResponseSerializer}
@@ -53,7 +53,7 @@ class QuotaGetMethod @Inject()(val metricFactory: 
MetricFactory,
     val requestedProperties: Properties = 
request.properties.getOrElse(JmapQuota.allProperties)
 
     (requestedProperties -- JmapQuota.allProperties match {
-      case invalidProperties if invalidProperties.isEmpty() => 
getQuotaGetResponse(request, mailboxSession.getUser)
+      case invalidProperties if invalidProperties.isEmpty() => 
getQuotaGetResponse(request, mailboxSession.getUser, capabilities)
         .reduce(QuotaResponseGetResult.empty)(QuotaResponseGetResult.merge)
         .map(result => result.asResponse(accountId = request.accountId))
         .map(response => Invocation(
@@ -77,15 +77,15 @@ class QuotaGetMethod @Inject()(val metricFactory: 
MetricFactory,
       case errors: JsError => Left(new 
IllegalArgumentException(ResponseSerializer.serialize(errors).toString))
     }
 
-  private def getQuotaGetResponse(quotaGetRequest: QuotaGetRequest, username: 
Username): SFlux[QuotaResponseGetResult] =
+  private def getQuotaGetResponse(quotaGetRequest: QuotaGetRequest, username: 
Username, capabilities: Set[CapabilityIdentifier]): 
SFlux[QuotaResponseGetResult] =
     quotaGetRequest.ids match {
       case None =>
-        jmapQuotaManagerWrapper.list(username)
+        jmapQuotaManagerWrapper.list(username, capabilities)
           .collectSeq()
           .map(listJmapQuota => QuotaResponseGetResult(jmapQuotaSet = 
listJmapQuota.toSet))
           .flatMapMany(result => SFlux.just(result))
       case Some(ids) => SFlux.fromIterable(ids.value)
-        .flatMap(id => jmapQuotaManagerWrapper.get(username, id.id)
+        .flatMap(id => jmapQuotaManagerWrapper.get(username, id.id, 
capabilities)
           .map(jmapQuota => QuotaResponseGetResult(jmapQuotaSet = 
Set(jmapQuota)))
           .switchIfEmpty(SMono.just(QuotaResponseGetResult(notFound = 
QuotaNotFound(Set(id))))))
     }
@@ -98,32 +98,39 @@ class QuotaGetMethod @Inject()(val metricFactory: 
MetricFactory,
 
 case class JmapQuotaManagerWrapper(private var quotaManager: QuotaManager,
                                    private var quotaRootResolver: 
UserQuotaRootResolver) {
-  def get(username: Username, quotaId: Id): SFlux[JmapQuota] =
-    SMono.just(quotaRootResolver.forUser(username))
-      .flatMapMany(quotaRoot => getJmapQuota(quotaRoot, Some(quotaId)))
+  def get(username: Username, quotaId: Id, capabilities: 
Set[CapabilityIdentifier]): SFlux[JmapQuota] =
+    retrieveQuotaRoot(username, capabilities)
+      .flatMap(quotaRoot => getJmapQuota(quotaRoot, Some(quotaId)))
 
-  def list(username: Username): SFlux[JmapQuota] =
-    SMono.just(quotaRootResolver.forUser(username))
-      .flatMapMany(quotaRoot => getJmapQuota(quotaRoot))
+  def list(username: Username, capabilities: Set[CapabilityIdentifier]): 
SFlux[JmapQuota] =
+    retrieveQuotaRoot(username, capabilities)
+      .flatMap(quotaRoot => getJmapQuota(quotaRoot))
+
+  def retrieveQuotaRoot(username: Username, capabilities: 
Set[CapabilityIdentifier]): SFlux[QuotaRoot] =
+    SMono.just(capabilities)
+      .map(value => value.contains(JAMES_SHARES))
+      .filter(containSharedCapability => containSharedCapability)
+      .flatMapMany(_ => 
SFlux(quotaRootResolver.listAllAccessibleQuotaRoots(username)))
+      .switchIfEmpty(SFlux.just(quotaRootResolver.forUser(username)))
 
   private def getJmapQuota(quotaRoot: QuotaRoot, quotaId: Option[Id] = None): 
SFlux[JmapQuota] =
     (quotaId match {
       case None => SMono(quotaManager.getQuotasReactive(quotaRoot))
-        .flatMapMany(quotas => SMono.fromCallable(() => 
JmapQuota.extractUserMessageCountQuota(quotas.getMessageQuota, 
QuotaIdFactory.from(quotaRoot, CountResourceType)))
-          .mergeWith(SMono.fromCallable(() => 
JmapQuota.extractUserMessageSizeQuota(quotas.getStorageQuota, 
QuotaIdFactory.from(quotaRoot, OctetsResourceType)))))
+        .flatMapMany(quotas => SMono.fromCallable(() => 
JmapQuota.extractUserMessageCountQuota(quotas.getMessageQuota, 
QuotaIdFactory.from(quotaRoot, CountResourceType), quotaRoot))
+          .mergeWith(SMono.fromCallable(() => 
JmapQuota.extractUserMessageSizeQuota(quotas.getStorageQuota, 
QuotaIdFactory.from(quotaRoot, OctetsResourceType), quotaRoot))))
 
       case Some(quotaIdValue) =>
         val quotaCountPublisher = SMono.fromCallable(() => 
QuotaIdFactory.from(quotaRoot, CountResourceType))
           .filter(countQuotaId => 
countQuotaId.value.equals(quotaIdValue.value))
           .flatMap(_ => SMono.fromCallable(() => 
quotaManager.getMessageQuota(quotaRoot))
             .subscribeOn(ReactorUtils.BLOCKING_CALL_WRAPPER))
-          .map(quota => JmapQuota.extractUserMessageCountQuota(quota, 
quotaIdValue))
+          .map(quota => JmapQuota.extractUserMessageCountQuota(quota, 
quotaIdValue, quotaRoot))
 
         val quotaSizePublisher = SMono.fromCallable(() => 
QuotaIdFactory.from(quotaRoot, OctetsResourceType))
           .filter(sizeQuotaId => sizeQuotaId.value.equals(quotaIdValue.value))
           .flatMap(_ => SMono.fromCallable(() => 
quotaManager.getStorageQuota(quotaRoot))
             .subscribeOn(ReactorUtils.BLOCKING_CALL_WRAPPER))
-          .map(quota => JmapQuota.extractUserMessageSizeQuota(quota, 
quotaIdValue))
+          .map(quota => JmapQuota.extractUserMessageSizeQuota(quota, 
quotaIdValue, quotaRoot))
 
         quotaCountPublisher.mergeWith(quotaSizePublisher)
     }).flatMap(SMono.justOrEmpty)


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to