You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/03/23 07:37:01 UTC
[james-project] 01/02: JAMES-3316 Allow custom properties payload
for custom capabilities in JMAP session
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 a29d8c1d32ba9a81adbed4420edfc4f055d6e8dc
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Mar 19 10:38:20 2021 +0700
JAMES-3316 Allow custom properties payload for custom capabilities in JMAP session
Currently, extra capability needed to have empty properties as the JSON generation
of the session capability payload was not modular.
We add an indirection level (the capability properties becomes JSON aware) in order to
permit that.
Session in a conveniant mean to convey information regarding JMAP extensions thus
customizing its payload is critical.
---
.../rfc8621/contract/CustomMethodContract.scala | 9 ++++--
.../org/apache/james/jmap/core/Capability.scala | 34 ++++++++++++++++-----
.../james/jmap/json/ResponseSerializer.scala | 35 ++++------------------
3 files changed, 38 insertions(+), 40 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/CustomMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/CustomMethodContract.scala
index f2f367d..b399781 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/CustomMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/CustomMethodContract.scala
@@ -40,6 +40,7 @@ import org.apache.james.mailbox.MailboxSession
import org.apache.james.utils.DataProbeImpl
import org.junit.jupiter.api.{BeforeEach, Test}
import org.reactivestreams.Publisher
+import play.api.libs.json.{JsObject, Json}
import reactor.core.scala.publisher.SMono
object CustomMethodContract {
@@ -75,7 +76,7 @@ object CustomMethodContract {
| "url": "http://domain.com/jmap/ws"
| },
| "urn:apache:james:params:jmap:mail:quota": {},
- | "$CUSTOM": {},
+ | "$CUSTOM": {"custom": "property"},
| "urn:apache:james:params:jmap:mail:shares": {},
| "urn:ietf:params:jmap:vacationresponse":{}
| },
@@ -113,7 +114,7 @@ object CustomMethodContract {
| },
| "urn:apache:james:params:jmap:mail:quota": {},
| "urn:apache:james:params:jmap:mail:shares": {},
- | "$CUSTOM": {},
+ | "$CUSTOM": {"custom": "property"},
| "urn:ietf:params:jmap:vacationresponse":{}
| }
| }
@@ -137,7 +138,9 @@ object CustomMethodContract {
|}""".stripMargin
}
-case class CustomCapabilityProperties() extends CapabilityProperties
+case class CustomCapabilityProperties() extends CapabilityProperties {
+ override def jsonify(): JsObject = Json.obj(("custom", "property"))
+}
case class CustomCapability(properties: CustomCapabilityProperties = CustomCapabilityProperties(), identifier: CapabilityIdentifier = CUSTOM) extends Capability
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Capability.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Capability.scala
index d3582bd..a73ad1a 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Capability.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/Capability.scala
@@ -30,7 +30,9 @@ import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, EM
import org.apache.james.jmap.core.CoreCapabilityProperties.CollationAlgorithm
import org.apache.james.jmap.core.MailCapability.EmailQuerySortOption
import org.apache.james.jmap.core.UnsignedInt.{UnsignedInt, UnsignedIntConstraint}
+import org.apache.james.jmap.json.ResponseSerializer
import org.apache.james.util.Size
+import play.api.libs.json.{JsObject, Json}
import scala.util.{Failure, Success, Try}
@@ -48,7 +50,9 @@ object CapabilityIdentifier {
val JAMES_SHARES: CapabilityIdentifier = "urn:apache:james:params:jmap:mail:shares"
}
-trait CapabilityProperties
+trait CapabilityProperties {
+ def jsonify(): JsObject
+}
trait Capability {
def identifier(): CapabilityIdentifier
@@ -86,10 +90,14 @@ final case class CoreCapabilityProperties(maxSizeUpload: MaxSizeUpload,
maxCallsInRequest: MaxCallsInRequest,
maxObjectsInGet: MaxObjectsInGet,
maxObjectsInSet: MaxObjectsInSet,
- collationAlgorithms: List[CollationAlgorithm]) extends CapabilityProperties
+ collationAlgorithms: List[CollationAlgorithm]) extends CapabilityProperties {
+ override def jsonify(): JsObject = ResponseSerializer.coreCapabilityWrites.writes(this)
+}
final case class WebSocketCapabilityProperties(supportsPush: SupportsPush,
- url: URL) extends CapabilityProperties
+ url: URL) extends CapabilityProperties {
+ override def jsonify(): JsObject = ResponseSerializer.webSocketPropertiesWrites.writes(this)
+}
final case class SupportsPush(value: Boolean) extends AnyVal
final case class MaxDelayedSend(value: Int) extends AnyVal
@@ -100,7 +108,9 @@ final case class SubmissionCapability(identifier: CapabilityIdentifier = EMAIL_S
properties: SubmissionProperties = SubmissionProperties()) extends Capability
final case class SubmissionProperties(maxDelayedSend: MaxDelayedSend = MaxDelayedSend(0),
- submissionExtensions: Map[EhloName, List[EhloArgs]] = Map()) extends CapabilityProperties
+ submissionExtensions: Map[EhloName, List[EhloArgs]] = Map()) extends CapabilityProperties {
+ override def jsonify(): JsObject = ResponseSerializer.submissionPropertiesWrites.writes(this)
+}
object MailCapability {
type EmailQuerySortOption = String Refined NonEmpty
@@ -120,19 +130,27 @@ final case class MailCapabilityProperties(maxMailboxesPerEmail: MaxMailboxesPerE
maxSizeMailboxName: MaxSizeMailboxName,
maxSizeAttachmentsPerEmail: MaxSizeAttachmentsPerEmail,
emailQuerySortOptions: List[EmailQuerySortOption],
- mayCreateTopLevelMailbox: MayCreateTopLevelMailbox) extends CapabilityProperties
+ mayCreateTopLevelMailbox: MayCreateTopLevelMailbox) extends CapabilityProperties {
+ override def jsonify(): JsObject = ResponseSerializer.mailCapabilityWrites.writes(this)
+}
-final case class QuotaCapabilityProperties() extends CapabilityProperties
+final case class QuotaCapabilityProperties() extends CapabilityProperties {
+ override def jsonify(): JsObject = Json.obj()
+}
final case class QuotaCapability(properties: QuotaCapabilityProperties = QuotaCapabilityProperties(),
identifier: CapabilityIdentifier = JAMES_QUOTA) extends Capability
-final case class SharesCapabilityProperties() extends CapabilityProperties
+final case class SharesCapabilityProperties() extends CapabilityProperties {
+ override def jsonify(): JsObject = Json.obj()
+}
final case class SharesCapability(properties: SharesCapabilityProperties = SharesCapabilityProperties(),
identifier: CapabilityIdentifier = JAMES_SHARES) extends Capability
-final case class VacationResponseCapabilityProperties() extends CapabilityProperties
+final case class VacationResponseCapabilityProperties() extends CapabilityProperties {
+ override def jsonify(): JsObject = Json.obj()
+}
final case class VacationResponseCapability(properties: VacationResponseCapabilityProperties = VacationResponseCapabilityProperties(),
identifier: CapabilityIdentifier = JMAP_VACATION_RESPONSE) extends Capability
\ No newline at end of file
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
index 89d4305..0c40307 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
@@ -88,42 +88,19 @@ object ResponseSerializer {
private implicit val usernameWrites: Writes[Username] = username => JsString(username.asString)
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]
+ val coreCapabilityWrites: OWrites[CoreCapabilityProperties] = Json.writes[CoreCapabilityProperties]
+ val mailCapabilityWrites: OWrites[MailCapabilityProperties] = Json.writes[MailCapabilityProperties]
private implicit val maxDelayedSendWrites: Writes[MaxDelayedSend] = Json.valueWrites[MaxDelayedSend]
private implicit val ehloNameWrites: Writes[EhloName] = Json.valueWrites[EhloName]
private implicit val ehloArgsWrites: Writes[EhloArgs] = Json.valueWrites[EhloArgs]
private implicit val supportsPushWrites: Writes[SupportsPush] = Json.valueWrites[SupportsPush]
- private implicit val submissionPropertiesWrites: Writes[SubmissionProperties] = Json.writes[SubmissionProperties]
- private implicit val webSocketPropertiesWrites: Writes[WebSocketCapabilityProperties] = Json.writes[WebSocketCapabilityProperties]
- private implicit val quotaCapabilityWrites: Writes[QuotaCapabilityProperties] = OWrites[QuotaCapabilityProperties](_ => Json.obj())
- private implicit val sharesCapabilityWrites: Writes[SharesCapabilityProperties] = OWrites[SharesCapabilityProperties](_ => Json.obj())
- private implicit val vacationResponseCapabilityWrites: Writes[VacationResponseCapabilityProperties] = OWrites[VacationResponseCapabilityProperties](_ => Json.obj())
- private implicit val submissionCapabilityWrites: Writes[SubmissionCapability] = OWrites[SubmissionCapability](_ => Json.obj())
- private implicit val webSocketCapabilityWrites: Writes[WebSocketCapability] = OWrites[WebSocketCapability](_ => Json.obj())
+ val submissionPropertiesWrites: OWrites[SubmissionProperties] = Json.writes[SubmissionProperties]
+ val webSocketPropertiesWrites: OWrites[WebSocketCapabilityProperties] = Json.writes[WebSocketCapabilityProperties]
private implicit val setCapabilityWrites: Writes[Set[_ <: Capability]] =
(set: Set[_ <: Capability]) => {
- set.foldLeft(JsObject.empty)((jsObject, capability) => {
- capability match {
- case capability: CoreCapability =>
- jsObject.+(capability.identifier.value, coreCapabilityWrites.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 capability: VacationResponseCapability =>
- jsObject.+(capability.identifier.value, vacationResponseCapabilityWrites.writes(capability.properties))
- case capability: SubmissionCapability =>
- jsObject.+(capability.identifier.value, submissionPropertiesWrites.writes(capability.properties))
- case capability: WebSocketCapability =>
- jsObject.+(capability.identifier.value, webSocketPropertiesWrites.writes(capability.properties))
- case _ =>
- jsObject.+(capability.identifier.value, JsObject(Map[String, JsValue]()))
- }
- })
+ set.foldLeft(JsObject.empty)((jsObject, capability) =>
+ jsObject.+(capability.identifier.value, capability.properties.jsonify))
}
private implicit val capabilitiesWrites: Writes[Capabilities] = capabilities => setCapabilityWrites.writes(capabilities.capabilities)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org