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]
