You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/07/06 01:37:07 UTC

[james-project] 05/05: JAMES-3096 filter properties depending on client provided capabilities

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 6139b01d25b5527f698d714a3cef9d69af869c54
Author: RĂ©mi KOWALSKI <rk...@linagora.com>
AuthorDate: Wed Jul 1 12:01:47 2020 +0200

    JAMES-3096 filter properties depending on client provided capabilities
---
 .../contract/MailboxGetMethodContract.scala        | 299 ++++++++++++++++++++-
 .../org/apache/james/jmap/json/Serializer.scala    |  24 +-
 .../apache/james/jmap/method/CoreEchoMethod.scala  |   3 +-
 .../james/jmap/method/MailboxGetMethod.scala       |  17 +-
 .../org/apache/james/jmap/method/Method.scala      |   3 +-
 .../org/apache/james/jmap/model/Capability.scala   |   6 +-
 .../apache/james/jmap/routes/JMAPApiRoutes.scala   |   7 +-
 .../jmap/json/MailboxGetSerializationTest.scala    |   4 +-
 .../james/jmap/json/MailboxSerializationTest.scala |   4 +-
 .../james/jmap/method/CoreEchoMethodTest.scala     |   8 +-
 10 files changed, 346 insertions(+), 29 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/MailboxGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
index b079138..e5e9b1f 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
@@ -65,6 +65,52 @@ object MailboxGetMethodContract {
     |      },
     |      "c1"]]
     |}""".stripMargin
+
+  private val GET_ALL_MAILBOXES_REQUEST_WITH_QUOTA: String =
+    """{
+    |  "using": [
+    |    "urn:ietf:params:jmap:core",
+    |    "urn:ietf:params:jmap:mail",
+    |    "urn:apache:james:params:jmap:mail:quota"],
+    |  "methodCalls": [[
+    |      "Mailbox/get",
+    |      {
+    |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+    |        "ids": null
+    |      },
+    |      "c1"]]
+    |}""".stripMargin
+
+  private val GET_ALL_MAILBOXES_REQUEST_WITH_SHARES: String =
+    """{
+    |  "using": [
+    |    "urn:ietf:params:jmap:core",
+    |    "urn:ietf:params:jmap:mail",
+    |    "urn:apache:james:params:jmap:mail:shares"],
+    |  "methodCalls": [[
+    |      "Mailbox/get",
+    |      {
+    |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+    |        "ids": null
+    |      },
+    |      "c1"]]
+    |}""".stripMargin
+
+  private val GET_ALL_MAILBOXES_REQUEST_WITH_BOTH: String =
+    """{
+    |  "using": [
+    |    "urn:ietf:params:jmap:core",
+    |    "urn:ietf:params:jmap:mail",
+    |    "urn:apache:james:params:jmap:mail:quota",
+    |    "urn:apache:james:params:jmap:mail:shares"],
+    |  "methodCalls": [[
+    |      "Mailbox/get",
+    |      {
+    |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+    |        "ids": null
+    |      },
+    |      "c1"]]
+    |}""".stripMargin
 }
 
 trait MailboxGetMethodContract {
@@ -131,6 +177,179 @@ trait MailboxGetMethodContract {
          |            "mayDelete": true,
          |            "maySubmit": true
          |          },
+         |          "isSubscribed": false
+         |        }
+         |      ],
+         |      "notFound": []
+         |    },
+         |    "c1"]]
+         |}""".stripMargin)
+  }
+
+  @Test
+  def getMailboxesShouldIncludeRightsAndNamespaceIfSharesCapabilityIsUsed(server: GuiceJamesServer): Unit = {
+    val mailboxId: String = server.getProbe(classOf[MailboxProbeImpl])
+      .createMailbox(MailboxPath.forUser(BOB, "custom"))
+      .serialize
+
+    val response: String = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(GET_ALL_MAILBOXES_REQUEST_WITH_SHARES)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response).isEqualTo(
+      s"""{
+         |  "sessionState": "75128aab4b1b",
+         |  "methodResponses": [[
+         |    "Mailbox/get",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "state": "000001",
+         |      "list": [
+         |        {
+         |          "id": "${mailboxId}",
+         |          "name": "custom",
+         |          "sortOrder": 1000,
+         |          "totalEmails": 0,
+         |          "unreadEmails": 0,
+         |          "totalThreads": 0,
+         |          "unreadThreads": 0,
+         |          "myRights": {
+         |            "mayReadItems": true,
+         |            "mayAddItems": true,
+         |            "mayRemoveItems": true,
+         |            "maySetSeen": true,
+         |            "maySetKeywords": true,
+         |            "mayCreateChild": true,
+         |            "mayRename": true,
+         |            "mayDelete": true,
+         |            "maySubmit": true
+         |          },
+         |          "isSubscribed": false,
+         |          "namespace": "Personal",
+         |          "rights": {}
+         |        }
+         |      ],
+         |      "notFound": []
+         |    },
+         |    "c1"]]
+         |}""".stripMargin)
+  }
+
+  @Test
+  def getMailboxesShouldIncludeQuotasIfQuotaCapabilityIsUsed(server: GuiceJamesServer): Unit = {
+    val mailboxId: String = server.getProbe(classOf[MailboxProbeImpl])
+      .createMailbox(MailboxPath.forUser(BOB, "custom"))
+      .serialize
+
+    val response: String = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(GET_ALL_MAILBOXES_REQUEST_WITH_QUOTA)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response).isEqualTo(
+      s"""{
+         |  "sessionState": "75128aab4b1b",
+         |  "methodResponses": [[
+         |    "Mailbox/get",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "state": "000001",
+         |      "list": [
+         |        {
+         |          "id": "${mailboxId}",
+         |          "name": "custom",
+         |          "sortOrder": 1000,
+         |          "totalEmails": 0,
+         |          "unreadEmails": 0,
+         |          "totalThreads": 0,
+         |          "unreadThreads": 0,
+         |          "myRights": {
+         |            "mayReadItems": true,
+         |            "mayAddItems": true,
+         |            "mayRemoveItems": true,
+         |            "maySetSeen": true,
+         |            "maySetKeywords": true,
+         |            "mayCreateChild": true,
+         |            "mayRename": true,
+         |            "mayDelete": true,
+         |            "maySubmit": true
+         |          },
+         |          "isSubscribed": false,
+         |          "quotas": {
+         |            "#private&bob@domain.tld": {
+         |              "Storage": { "used": 0},
+         |              "Message": {"used": 0}
+         |            }
+         |          }
+         |        }
+         |      ],
+         |      "notFound": []
+         |    },
+         |    "c1"]]
+         |}""".stripMargin)
+  }
+
+  @Test
+  def getMailboxesShouldIncludeBothQuotasAndRightsIfUsed(server: GuiceJamesServer): Unit = {
+    val mailboxId: String = server.getProbe(classOf[MailboxProbeImpl])
+      .createMailbox(MailboxPath.forUser(BOB, "custom"))
+      .serialize
+
+    val response: String = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(GET_ALL_MAILBOXES_REQUEST_WITH_BOTH)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response).isEqualTo(
+      s"""{
+         |  "sessionState": "75128aab4b1b",
+         |  "methodResponses": [[
+         |    "Mailbox/get",
+         |    {
+         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "state": "000001",
+         |      "list": [
+         |        {
+         |          "id": "${mailboxId}",
+         |          "name": "custom",
+         |          "sortOrder": 1000,
+         |          "totalEmails": 0,
+         |          "unreadEmails": 0,
+         |          "totalThreads": 0,
+         |          "unreadThreads": 0,
+         |          "myRights": {
+         |            "mayReadItems": true,
+         |            "mayAddItems": true,
+         |            "mayRemoveItems": true,
+         |            "maySetSeen": true,
+         |            "maySetKeywords": true,
+         |            "mayCreateChild": true,
+         |            "mayRename": true,
+         |            "mayDelete": true,
+         |            "maySubmit": true
+         |          },
          |          "isSubscribed": false,
          |          "namespace": "Personal",
          |          "rights": {},
@@ -225,7 +444,7 @@ trait MailboxGetMethodContract {
 
     `given`
       .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
-      .body(GET_ALL_MAILBOXES_REQUEST)
+      .body(GET_ALL_MAILBOXES_REQUEST_WITH_SHARES)
     .when
       .post
     .`then`
@@ -250,7 +469,7 @@ trait MailboxGetMethodContract {
 
     `given`
       .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
-      .body(GET_ALL_MAILBOXES_REQUEST)
+      .body(GET_ALL_MAILBOXES_REQUEST_WITH_SHARES)
     .when
       .post
     .`then`
@@ -278,7 +497,7 @@ trait MailboxGetMethodContract {
 
     `given`
       .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
-      .body(GET_ALL_MAILBOXES_REQUEST)
+      .body(GET_ALL_MAILBOXES_REQUEST_WITH_SHARES)
     .when
       .post
     .`then`
@@ -389,7 +608,7 @@ trait MailboxGetMethodContract {
 
     `given`
       .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
-      .body(GET_ALL_MAILBOXES_REQUEST)
+      .body(GET_ALL_MAILBOXES_REQUEST_WITH_QUOTA)
     .when
       .post
     .`then`
@@ -415,7 +634,7 @@ trait MailboxGetMethodContract {
 
     `given`
       .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
-      .body(GET_ALL_MAILBOXES_REQUEST)
+      .body(GET_ALL_MAILBOXES_REQUEST_WITH_QUOTA)
     .when
       .post
     .`then`
@@ -462,7 +681,9 @@ trait MailboxGetMethodContract {
       .body(s"""{
                |  "using": [
                |    "urn:ietf:params:jmap:core",
-               |    "urn:ietf:params:jmap:mail"],
+               |    "urn:ietf:params:jmap:mail",
+               |    "urn:apache:james:params:jmap:mail:quota",
+               |    "urn:apache:james:params:jmap:mail:shares"],
                |  "methodCalls": [[
                |    "Mailbox/get",
                |    {
@@ -526,6 +747,72 @@ trait MailboxGetMethodContract {
   }
 
   @Test
+  def getMailboxesByIdsShouldReturnCorrespondingMailboxWithoutPropertiesFromNotProvidedCapabilities(server: GuiceJamesServer): Unit = {
+    val mailboxId: String = server.getProbe(classOf[MailboxProbeImpl])
+      .createMailbox(MailboxPath.forUser(BOB, "custom"))
+      .serialize
+
+    val response: String = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(s"""{
+               |  "using": [
+               |    "urn:ietf:params:jmap:core",
+               |    "urn:ietf:params:jmap:mail"],
+               |  "methodCalls": [[
+               |    "Mailbox/get",
+               |    {
+               |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+               |      "ids": ["${mailboxId}"]
+               |    },
+               |    "c1"]]
+               |}""".stripMargin)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response).isEqualTo(
+      s"""{
+         |  "sessionState": "75128aab4b1b",
+         |  "methodResponses": [[
+         |    "Mailbox/get",
+         |      {
+         |        "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |        "state": "000001",
+         |        "list": [
+         |          {
+         |            "id": "${mailboxId}",
+         |            "name": "custom",
+         |            "sortOrder": 1000,
+         |            "totalEmails": 0,
+         |            "unreadEmails": 0,
+         |            "totalThreads": 0,
+         |            "unreadThreads": 0,
+         |            "myRights": {
+         |              "mayReadItems": true,
+         |              "mayAddItems": true,
+         |              "mayRemoveItems": true,
+         |              "maySetSeen": true,
+         |              "maySetKeywords": true,
+         |              "mayCreateChild": true,
+         |              "mayRename": true,
+         |              "mayDelete": true,
+         |              "maySubmit": true
+         |            },
+         |            "isSubscribed": false
+         |          }
+         |        ],
+         |        "notFound": []
+         |      },
+         |      "c1"]]
+         |}""".stripMargin)
+  }
+
+  @Test
   def getMailboxesByIdsShouldReturnOnlyRequestedMailbox(server: GuiceJamesServer): Unit = {
     val mailboxName: String = "custom"
     val mailboxId: String = server.getProbe(classOf[MailboxProbeImpl])
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala
index e6d26e3..ad6b6b5 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala
@@ -201,7 +201,8 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
       })
     }
 
-  private implicit val mailboxWrites: Writes[Mailbox] = Json.writes[Mailbox]
+  implicit def mailboxWrites(propertiesToHide: Set[String]): Writes[Mailbox] = Json.writes[Mailbox]
+    .transform((o: JsObject) => JsObject(o.fields.filterNot(entry => propertiesToHide.contains(entry._1))))
 
   private implicit val idsRead: Reads[Ids] = Json.valueReads[Ids]
   private implicit val propertiesRead: Reads[Properties] = Json.valueReads[Properties]
@@ -210,7 +211,7 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
   private implicit def notFoundWrites(implicit mailboxIdWrites: Writes[MailboxId]): Writes[NotFound] =
     notFound => JsArray(notFound.value.toList.map(mailboxIdWrites.writes))
 
-  private implicit val mailboxGetResponseWrites: Writes[MailboxGetResponse] = Json.writes[MailboxGetResponse]
+  private implicit def mailboxGetResponseWrites(implicit mailboxWrites: Writes[Mailbox]): Writes[MailboxGetResponse] = Json.writes[MailboxGetResponse]
 
   private implicit val jsonValidationErrorWrites: Writes[JsonValidationError] = error => JsString(error.message)
 
@@ -229,6 +230,17 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
       })
     }
 
+  private def mailboxWritesWithFilteredProperties(capabilities: Set[CapabilityIdentifier]): Writes[Mailbox] = {
+    val propertiesForCapabitilites: Map[CapabilityIdentifier, Set[String]] = Map(
+      CapabilityIdentifier.JAMES_QUOTA -> Set("quotas"),
+      CapabilityIdentifier.JAMES_SHARES -> Set("namespace", "rights")
+    )
+    val propertiesToHide = propertiesForCapabitilites.filterNot(entry => capabilities.contains(entry._1))
+      .flatMap(_._2)
+      .toSet
+    mailboxWrites(propertiesToHide)
+  }
+
   private implicit def jsErrorWrites: Writes[JsError] = Json.writes[JsError]
 
   def serialize(session: Session): JsValue = Json.toJson(session)
@@ -237,9 +249,13 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
 
   def serialize(responseObject: ResponseObject): JsValue = Json.toJson(responseObject)
 
-  def serialize(mailbox: Mailbox): JsValue = Json.toJson(mailbox)
+  def serialize(mailbox: Mailbox)(implicit mailboxWrites: Writes[Mailbox]): JsValue = Json.toJson(mailbox)
 
-  def serialize(mailboxGetResponse: MailboxGetResponse): JsValue = Json.toJson(mailboxGetResponse)
+  def serialize(mailboxGetResponse: MailboxGetResponse)(implicit mailboxWrites: Writes[Mailbox]): JsValue = Json.toJson(mailboxGetResponse)
+
+  def serialize(mailboxGetResponse: MailboxGetResponse, capabilities: Set[CapabilityIdentifier]): JsValue = {
+    serialize(mailboxGetResponse)(mailboxWritesWithFilteredProperties(capabilities))
+  }
 
   def serialize(errors: JsError): JsValue = Json.toJson(errors)
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
index fad57d8..d1dd286 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
@@ -20,6 +20,7 @@ package org.apache.james.jmap.method
 
 
 import eu.timepit.refined.auto._
+import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.model.Invocation
 import org.apache.james.jmap.model.Invocation.MethodName
 import org.apache.james.mailbox.MailboxSession
@@ -29,5 +30,5 @@ import reactor.core.scala.publisher.SMono
 class CoreEchoMethod extends Method {
   override val methodName = MethodName("Core/echo")
 
-  override def process(invocation: Invocation, mailboxSession: MailboxSession): Publisher[Invocation] = SMono.just(invocation)
+  override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession): Publisher[Invocation] = SMono.just(invocation)
 }
\ No newline at end of file
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
index b3c66c1..168b095 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
@@ -23,6 +23,7 @@ import eu.timepit.refined.auto._
 import javax.inject.Inject
 import org.apache.james.jmap.json.Serializer
 import org.apache.james.jmap.mail._
+import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
 import org.apache.james.jmap.model.State.INSTANCE
 import org.apache.james.jmap.model.{Invocation, MailboxFactory}
@@ -53,7 +54,7 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
     def merge(other: MailboxGetResults): MailboxGetResults = MailboxGetResults(this.mailboxes ++ other.mailboxes, this.notFound.merge(other.notFound))
   }
 
-  override def process(invocation: Invocation, mailboxSession: MailboxSession): Publisher[Invocation] = {
+  override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession): Publisher[Invocation] = {
     metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
       asMailboxGetRequest(invocation.arguments)
         .flatMap(mailboxGetRequest => getMailboxes(mailboxGetRequest, mailboxSession)
@@ -65,7 +66,7 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
             notFound = mailboxes.notFound))
           .map(mailboxGetResponse => Invocation(
             methodName = methodName,
-            arguments = Arguments(serializer.serialize(mailboxGetResponse).as[JsObject]),
+            arguments = Arguments(serializer.serialize(mailboxGetResponse, capabilities).as[JsObject]),
             methodCallId = invocation.methodCallId))))
   }
 
@@ -76,11 +77,13 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
     }
   }
 
-  private def getMailboxes(mailboxGetRequest: MailboxGetRequest, mailboxSession: MailboxSession): SFlux[MailboxGetResults] = mailboxGetRequest.ids match {
-    case None => getAllMailboxes(mailboxSession).map(MailboxGetResults.found)
-    case Some(ids) => SFlux.fromIterable(ids.value)
-      .flatMap(id => getMailboxResultById(id, mailboxSession))
-  }
+  private def getMailboxes(mailboxGetRequest: MailboxGetRequest,
+                           mailboxSession: MailboxSession): SFlux[MailboxGetResults] =
+    mailboxGetRequest.ids match {
+      case None => getAllMailboxes(mailboxSession).map(MailboxGetResults.found)
+      case Some(ids) => SFlux.fromIterable(ids.value)
+        .flatMap(id => getMailboxResultById(id, mailboxSession))
+    }
 
   private def getMailboxResultById(mailboxId: MailboxId, mailboxSession: MailboxSession): SMono[MailboxGetResults] =
     quotaFactory.loadFor(mailboxSession)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
index 02751dc..078929e 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
@@ -19,6 +19,7 @@
 package org.apache.james.jmap.method
 
 
+import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.model.Invocation
 import org.apache.james.jmap.model.Invocation.MethodName
 import org.apache.james.mailbox.MailboxSession
@@ -29,6 +30,6 @@ trait Method {
 
   val methodName: MethodName
 
-  def process(invocation: Invocation, mailboxSession: MailboxSession): Publisher[Invocation]
+  def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession): Publisher[Invocation]
 }
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/Capability.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/Capability.scala
index 17517fe..6fd841c 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/Capability.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/Capability.scala
@@ -30,8 +30,10 @@ import org.apache.james.jmap.model.UnsignedInt.UnsignedInt
 
 object CapabilityIdentifier {
   type CapabilityIdentifier = String Refined Uri
-  private[model] val JMAP_CORE: CapabilityIdentifier = "urn:ietf:params:jmap:core"
-  private[model] val JMAP_MAIL: CapabilityIdentifier = "urn:ietf:params:jmap:mail"
+  val JMAP_CORE: CapabilityIdentifier = "urn:ietf:params:jmap:core"
+  val JMAP_MAIL: CapabilityIdentifier = "urn:ietf:params:jmap:mail"
+  val JAMES_QUOTA: CapabilityIdentifier = "urn:apache:james:params:jmap:mail:quota"
+  val JAMES_SHARES: CapabilityIdentifier = "urn:apache:james:params:jmap:mail:shares"
 }
 
 sealed trait CapabilityProperties
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
index dc918c6..0a89a16 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
@@ -36,6 +36,7 @@ import org.apache.james.jmap.http.Authenticator
 import org.apache.james.jmap.http.rfc8621.InjectionKeys
 import org.apache.james.jmap.json.Serializer
 import org.apache.james.jmap.method.Method
+import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
 import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
 import org.apache.james.jmap.model.{Invocation, RequestObject, ResponseObject}
 import org.apache.james.jmap.{Endpoint, JMAPRoute, JMAPRoutes}
@@ -104,7 +105,7 @@ class JMAPApiRoutes (val authenticator: Authenticator,
                       mailboxSession: MailboxSession): SMono[Void] =
     requestObject
       .methodCalls
-      .map(invocation => this.processMethodWithMatchName(invocation, mailboxSession))
+      .map(invocation => this.processMethodWithMatchName(requestObject.using.toSet, invocation, mailboxSession))
       .foldLeft(SFlux.empty[Invocation]) { (flux: SFlux[Invocation], mono: SMono[Invocation]) => flux.mergeWith(mono) }
       .collectSeq()
       .flatMap((invocations: Seq[Invocation]) =>
@@ -117,9 +118,9 @@ class JMAPApiRoutes (val authenticator: Authenticator,
           ).`then`())
       )
 
-  private def processMethodWithMatchName(invocation: Invocation, mailboxSession: MailboxSession): SMono[Invocation] =
+  private def processMethodWithMatchName(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession): SMono[Invocation] =
     SMono.justOrEmpty(methodsByName.get(invocation.methodName))
-      .flatMap(method => SMono.fromPublisher(method.process(invocation, mailboxSession)))
+      .flatMap(method => SMono.fromPublisher(method.process(capabilities, invocation, mailboxSession)))
       .switchIfEmpty(SMono.just(new Invocation(
         MethodName("error"),
         Arguments(Json.obj("type" -> "Not implemented")),
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala
index b27f06b..c2da125 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala
@@ -42,6 +42,8 @@ object MailboxGetSerializationTest {
   private val MAILBOX_ID_2: MailboxId = FACTORY.fromString("2")
 
   private val PROPERTIES: Properties = Properties(List("name", "role"))
+
+  private val NO_PROPERTY_FILTERING: Set[String] = Set.empty
 }
 
 class MailboxGetSerializationTest extends AnyWordSpec with Matchers {
@@ -205,7 +207,7 @@ class MailboxGetSerializationTest extends AnyWordSpec with Matchers {
           |}
           |""".stripMargin
 
-      assertThatJson(Json.stringify(SERIALIZER.serialize(actualValue))).isEqualTo(expectedJson)
+      assertThatJson(Json.stringify(SERIALIZER.serialize(actualValue)(SERIALIZER.mailboxWrites(NO_PROPERTY_FILTERING)))).isEqualTo(expectedJson)
     }
   }
 }
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxSerializationTest.scala
index c5b49d8..99455a6 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxSerializationTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxSerializationTest.scala
@@ -129,7 +129,9 @@ class MailboxSerializationTest extends AnyWordSpec with Matchers {
           |  }
           |}""".stripMargin
 
-      assertThatJson(Json.stringify(new Serializer(new TestId.Factory).serialize(MAILBOX))).isEqualTo(expectedJson)
+      val serializer = new Serializer(new TestId.Factory)
+      val noPropertyFiltering: Set[String] = Set.empty
+      assertThatJson(Json.stringify(serializer.serialize(MAILBOX)(serializer.mailboxWrites(noPropertyFiltering)))).isEqualTo(expectedJson)
     }
   }
 }
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
index 583e832..9415c16 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
@@ -19,7 +19,8 @@
 package org.apache.james.jmap.method
 
 import org.apache.james.jmap.json.Fixture.{invocation1, invocation2}
-import org.apache.james.jmap.model.Invocation
+import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
+import org.apache.james.jmap.model.{CapabilityIdentifier, Invocation}
 import org.apache.james.mailbox.MailboxSession
 import org.mockito.Mockito.mock
 import org.scalatest.matchers.should.Matchers
@@ -29,19 +30,20 @@ import reactor.core.scala.publisher.SMono
 class CoreEchoMethodTest extends AnyWordSpec with Matchers {
   private val echoMethod: CoreEchoMethod = new CoreEchoMethod()
   private val mockedSession: MailboxSession = mock(classOf[MailboxSession])
+  private val capabilities: Set[CapabilityIdentifier] = Set(CapabilityIdentifier.JMAP_CORE, CapabilityIdentifier.JMAP_MAIL)
 
   "CoreEcho" should {
     "Process" should {
       "success and return the same with parameters as the invocation request" in {
         val expectedResponse: Invocation = invocation1
-        val dataResponse = SMono.fromPublisher(echoMethod.process(invocation1, mockedSession)).block()
+        val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, invocation1, mockedSession)).block()
 
         dataResponse shouldBe expectedResponse
       }
 
       "success and not return anything else different than the original invocation" in {
         val wrongExpected: Invocation = invocation2
-        val dataResponse = SMono.fromPublisher(echoMethod.process(invocation1, mockedSession)).block()
+        val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, invocation1, mockedSession)).block()
         
         dataResponse should not be(wrongExpected)
       }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org