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/30 04:15:15 UTC

[james-project] 02/12: JAMES-2892 use the same default capabilities everywhere

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 6867c94624466b4ed217be3d267b60456ad9fad7
Author: Raphael Ouazana <ra...@linagora.com>
AuthorDate: Thu Jul 23 17:13:29 2020 +0200

    JAMES-2892 use the same default capabilities everywhere
---
 .../org/apache/james/jmap/json/Serializer.scala    | 12 +++-
 .../org/apache/james/jmap/model/Capabilities.scala | 13 ++++-
 .../org/apache/james/jmap/model/Capability.scala   | 18 +++++-
 .../apache/james/jmap/routes/JMAPApiRoutes.scala   |  2 +-
 .../apache/james/jmap/http/SessionRoutesTest.scala | 68 +++++++++++++++++++++-
 .../james/jmap/json/SessionSerializationTest.scala |  6 +-
 6 files changed, 106 insertions(+), 13 deletions(-)

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 d9e234a..614c6fa 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
@@ -93,9 +93,13 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
   private implicit val urlWrites: Writes[URL] = url => JsString(url.toString)
   private implicit val coreCapabilityWrites: Writes[CoreCapabilityProperties] = Json.writes[CoreCapabilityProperties]
   private implicit val mailCapabilityWrites: Writes[MailCapabilityProperties] = Json.writes[MailCapabilityProperties]
+  private implicit val quotaCapabilityWrites: Writes[QuotaCapabilityProperties] = OWrites[QuotaCapabilityProperties](_ => Json.obj())
+  private implicit val sharesCapabilityWrites: Writes[SharesCapabilityProperties] = OWrites[SharesCapabilityProperties](_ => Json.obj())
 
   private implicit def setCapabilityWrites(implicit corePropertiesWriter: Writes[CoreCapabilityProperties],
-                                   mailCapabilityWrites: Writes[MailCapabilityProperties]): Writes[Set[_ <: Capability]] =
+                                   mailCapabilityWrites: Writes[MailCapabilityProperties],
+                                   quotaCapabilityWrites: Writes[QuotaCapabilityProperties],
+                                   sharesCapabilityWrites: Writes[SharesCapabilityProperties]): Writes[Set[_ <: Capability]] =
     (set: Set[_ <: Capability]) => {
       set.foldLeft(JsObject.empty)((jsObject, capability) => {
         capability match {
@@ -103,12 +107,16 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
             jsObject.+(capability.identifier.value, corePropertiesWriter.writes(capability.properties)))
           case capability: MailCapability => (
             jsObject.+(capability.identifier.value, mailCapabilityWrites.writes(capability.properties)))
+          case capability: QuotaCapability => (
+            jsObject.+(capability.identifier.value, quotaCapabilityWrites.writes(capability.properties)))
+          case capability: SharesCapability => (
+            jsObject.+(capability.identifier.value, sharesCapabilityWrites.writes(capability.properties)))
           case _ => jsObject
         }
       })
     }
 
-  private implicit val capabilitiesWrites: Writes[Capabilities] = capabilities => setCapabilityWrites.writes(Set(capabilities.coreCapability, capabilities.mailCapability))
+  private implicit val capabilitiesWrites: Writes[Capabilities] = capabilities => setCapabilityWrites.writes(capabilities.toSet)
 
   private implicit val accountIdWrites: Format[AccountId] = Json.valueFormat[AccountId]
   private implicit def identifierMapWrite[Any](implicit idWriter: Writes[AccountId]): Writes[Map[CapabilityIdentifier, Any]] =
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/Capabilities.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/Capabilities.scala
index ac0a7d4..9fe910f 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/Capabilities.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/Capabilities.scala
@@ -19,6 +19,7 @@
 package org.apache.james.jmap.model
 
 import eu.timepit.refined.auto._
+import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
 
 object DefaultCapabilities {
   val CORE_CAPABILITY = CoreCapability(
@@ -43,9 +44,15 @@ object DefaultCapabilities {
     )
   )
 
-  val SUPPORTED = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
+  val QUOTA_CAPABILITY = QuotaCapability()
+
+  val SHARES_CAPABILITY = SharesCapability()
+
+  val SUPPORTED = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY, QUOTA_CAPABILITY, SHARES_CAPABILITY)
 }
 
-case class Capabilities(coreCapability: CoreCapability, mailCapability: MailCapability) {
-  def toSet : Set[Capability] = Set(coreCapability, mailCapability)
+case class Capabilities(capabilities: Capability*) {
+  def toSet : Set[Capability] = capabilities.toSet
+
+  def ids : Set[CapabilityIdentifier] = toSet.map(_.identifier())
 }
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 8eaaefb..1ade76e 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
@@ -23,7 +23,7 @@ import eu.timepit.refined.api.Refined
 import eu.timepit.refined.auto._
 import eu.timepit.refined.collection.NonEmpty
 import eu.timepit.refined.string.Uri
-import org.apache.james.jmap.model.CapabilityIdentifier.{CapabilityIdentifier, JMAP_CORE, JMAP_MAIL}
+import org.apache.james.jmap.model.CapabilityIdentifier.{CapabilityIdentifier, JMAP_CORE, JMAP_MAIL, JAMES_QUOTA, JAMES_SHARES}
 import org.apache.james.jmap.model.CoreCapabilityProperties.CollationAlgorithm
 import org.apache.james.jmap.model.MailCapability.EmailQuerySortOption
 import org.apache.james.jmap.model.UnsignedInt.UnsignedInt
@@ -34,8 +34,6 @@ object CapabilityIdentifier {
   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"
-
-  val SUPPORTED_CAPABILITIES: Set[CapabilityIdentifier] = Set(JMAP_CORE, JMAP_MAIL, JAMES_QUOTA, JAMES_SHARES)
 }
 
 sealed trait CapabilityProperties
@@ -91,3 +89,17 @@ final case class MailCapabilityProperties(maxMailboxesPerEmail: MaxMailboxesPerE
                                           mayCreateTopLevelMailbox: MayCreateTopLevelMailbox) extends CapabilityProperties {
 }
 
+final case class QuotaCapabilityProperties() extends CapabilityProperties {
+}
+
+final case class QuotaCapability(properties: QuotaCapabilityProperties = QuotaCapabilityProperties(),
+                                 identifier: CapabilityIdentifier = JAMES_QUOTA) extends Capability {
+}
+
+final case class SharesCapabilityProperties() extends CapabilityProperties {
+}
+
+final case class SharesCapability(properties: SharesCapabilityProperties = SharesCapabilityProperties(),
+                                  identifier: CapabilityIdentifier = JAMES_SHARES) extends Capability {
+}
+
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 45dfda5..320c540 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
@@ -104,7 +104,7 @@ class JMAPApiRoutes (val authenticator: Authenticator,
   private def process(requestObject: RequestObject,
                       httpServerResponse: HttpServerResponse,
                       mailboxSession: MailboxSession): SMono[Void] = {
-    val unsupportedCapabilities = requestObject.using.toSet -- CapabilityIdentifier.SUPPORTED_CAPABILITIES
+    val unsupportedCapabilities = requestObject.using.toSet -- DefaultCapabilities.SUPPORTED.ids
 
     if (unsupportedCapabilities.nonEmpty) {
       SMono.raiseError(UnsupportedCapabilitiesException(unsupportedCapabilities))
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/http/SessionRoutesTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/http/SessionRoutesTest.scala
index 0501f8b..47e89ee 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/http/SessionRoutesTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/http/SessionRoutesTest.scala
@@ -31,7 +31,6 @@ import org.apache.http.HttpStatus
 import org.apache.james.core.Username
 import org.apache.james.jmap._
 import org.apache.james.jmap.http.SessionRoutesTest.{BOB, TEST_CONFIGURATION}
-import org.apache.james.jmap.json.Fixture.expected_session_object_json
 import org.apache.james.jmap.json.Serializer
 import org.apache.james.mailbox.MailboxSession
 import org.apache.james.mailbox.model.TestId
@@ -101,7 +100,72 @@ class SessionRoutesTest extends AnyFlatSpec with BeforeAndAfter with Matchers {
       .thenReturn
         .getBody
         .asString()
+    val expectedJson = """{
+                         |  "capabilities" : {
+                         |    "urn:ietf:params:jmap:core" : {
+                         |      "maxSizeUpload" : 10000000,
+                         |      "maxConcurrentUpload" : 4,
+                         |      "maxSizeRequest" : 10000000,
+                         |      "maxConcurrentRequests" : 4,
+                         |      "maxCallsInRequest" : 16,
+                         |      "maxObjectsInGet" : 500,
+                         |      "maxObjectsInSet" : 500,
+                         |      "collationAlgorithms" : [ "i;unicode-casemap" ]
+                         |    },
+                         |    "urn:ietf:params:jmap:mail" : {
+                         |      "maxMailboxesPerEmail" : 10000000,
+                         |      "maxMailboxDepth" : null,
+                         |      "maxSizeMailboxName" : 200,
+                         |      "maxSizeAttachmentsPerEmail" : 20000000,
+                         |      "emailQuerySortOptions" : [ "receivedAt", "cc", "from", "to", "subject", "size", "sentAt", "hasKeyword", "uid", "Id" ],
+                         |      "mayCreateTopLevelMailbox" : true
+                         |    },
+                         |    "urn:apache:james:params:jmap:mail:quota": {},
+                         |    "urn:apache:james:params:jmap:mail:shares": {}
+                         |  },
+                         |  "accounts" : {
+                         |    "0fe275bf13ff761407c17f64b1dfae2f4b3186feea223d7267b79f873a105401" : {
+                         |      "name" : "bob@james.org",
+                         |      "isPersonal" : true,
+                         |      "isReadOnly" : false,
+                         |      "accountCapabilities" : {
+                         |        "urn:ietf:params:jmap:core" : {
+                         |          "maxSizeUpload" : 10000000,
+                         |          "maxConcurrentUpload" : 4,
+                         |          "maxSizeRequest" : 10000000,
+                         |          "maxConcurrentRequests" : 4,
+                         |          "maxCallsInRequest" : 16,
+                         |          "maxObjectsInGet" : 500,
+                         |          "maxObjectsInSet" : 500,
+                         |          "collationAlgorithms" : [ "i;unicode-casemap" ]
+                         |        },
+                         |        "urn:ietf:params:jmap:mail" : {
+                         |          "maxMailboxesPerEmail" : 10000000,
+                         |          "maxMailboxDepth" : null,
+                         |          "maxSizeMailboxName" : 200,
+                         |          "maxSizeAttachmentsPerEmail" : 20000000,
+                         |          "emailQuerySortOptions" : [ "receivedAt", "cc", "from", "to", "subject", "size", "sentAt", "hasKeyword", "uid", "Id" ],
+                         |          "mayCreateTopLevelMailbox" : true
+                         |        },
+                         |        "urn:apache:james:params:jmap:mail:quota": {},
+                         |        "urn:apache:james:params:jmap:mail:shares": {}
+                         |      }
+                         |    }
+                         |  },
+                         |  "primaryAccounts" : {
+                         |    "urn:ietf:params:jmap:core" : "0fe275bf13ff761407c17f64b1dfae2f4b3186feea223d7267b79f873a105401",
+                         |    "urn:ietf:params:jmap:mail" : "0fe275bf13ff761407c17f64b1dfae2f4b3186feea223d7267b79f873a105401",
+                         |    "urn:apache:james:params:jmap:mail:quota": "0fe275bf13ff761407c17f64b1dfae2f4b3186feea223d7267b79f873a105401",
+                         |    "urn:apache:james:params:jmap:mail:shares": "0fe275bf13ff761407c17f64b1dfae2f4b3186feea223d7267b79f873a105401"
+                         |  },
+                         |  "username" : "bob@james.org",
+                         |  "apiUrl" : "http://this-url-is-hardcoded.org/jmap",
+                         |  "downloadUrl" : "http://this-url-is-hardcoded.org/download",
+                         |  "uploadUrl" : "http://this-url-is-hardcoded.org/upload",
+                         |  "eventSourceUrl" : "http://this-url-is-hardcoded.org/eventSource",
+                         |  "state" : "000001"
+                         |}""".stripMargin
 
-    Json.parse(sessionJson) should equal(expected_session_object_json)
+    Json.parse(sessionJson) should equal(Json.parse(expectedJson))
   }
 }
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/SessionSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/SessionSerializationTest.scala
index 5a418d8..6daaa45 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/SessionSerializationTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/SessionSerializationTest.scala
@@ -79,7 +79,7 @@ object SessionSerializationTest {
     emailQuerySortOptions = EMAIL_QUERY_SORT_OPTIONS,
     mayCreateTopLevelMailbox = MAY_CREATE_TOP_LEVEL_MAILBOX))
 
-  private val CAPABILITIES = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
+  private val CAPABILITIES = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY, QuotaCapability(), SharesCapability())
 
   private val IS_PERSONAL : IsPersonal = IsPersonal(true)
   private val IS_NOT_PERSONAL : IsPersonal = IsPersonal(false)
@@ -148,7 +148,9 @@ class SessionSerializationTest extends AnyWordSpec with Matchers {
           |      "maxSizeAttachmentsPerEmail": 890099,
           |      "emailQuerySortOptions": ["size"],
           |      "mayCreateTopLevelMailbox": true
-          |    }
+          |    },
+          |    "urn:apache:james:params:jmap:mail:quota":{},
+          |    "urn:apache:james:params:jmap:mail:shares":{}
           |  },
           |  "accounts": {
           |    "807a5306ccb4527af7790a0f9b48a776514bdbfba064e355461a76bcffbf2c90": {


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