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/02/09 04:29:54 UTC
[james-project] 26/33: JAMES-3491 Enabling push should not reject
unhandled data types
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 ebc6e0e3aa62c210b5bd00c1a3711c9ef3495081
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Feb 5 12:09:18 2021 +0700
JAMES-3491 Enabling push should not reject unhandled data types
Rejection of specified data types we do not yet send notifications for would cause a breaking behaviours in clients registrating them.
---
.../jmap/rfc8621/contract/WebSocketContract.scala | 70 ++++++++++++++++++++++
.../org/apache/james/jmap/change/StateChange.scala | 17 +++++-
.../james/jmap/json/ResponseSerializer.scala | 7 ++-
3 files changed, 92 insertions(+), 2 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/WebSocketContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/WebSocketContract.scala
index 750c12f..5fd55a0 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/WebSocketContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/WebSocketContract.scala
@@ -502,6 +502,76 @@ trait WebSocketContract {
}
@Test
+ // For client compatibility purposes
+ def specifiedUnHandledDataTypesShouldNotBeRejected(server: GuiceJamesServer): Unit = {
+ val bobPath = MailboxPath.inbox(BOB)
+ val accountId: AccountId = AccountId.fromUsername(BOB)
+ val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath)
+
+ Thread.sleep(100)
+
+ val response: Either[String, List[String]] =
+ authenticatedRequest(server)
+ .response(asWebSocket[Identity, List[String]] {
+ ws =>
+ ws.send(WebSocketFrame.text(
+ """{
+ | "@type": "WebSocketPushEnable",
+ | "dataTypes": ["Mailbox", "Email", "VacationResponse", "Thread", "Identity", "EmailSubmission", "EmailDelivery"]
+ |}""".stripMargin))
+
+ Thread.sleep(100)
+
+ ws.send(WebSocketFrame.text(
+ s"""{
+ | "@type": "Request",
+ | "requestId": "req-36",
+ | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [
+ | ["Email/set", {
+ | "accountId": "$ACCOUNT_ID",
+ | "create": {
+ | "aaaaaa":{
+ | "mailboxIds": {
+ | "${mailboxId.serialize}": true
+ | }
+ | }
+ | }
+ | }, "c1"]]
+ |}""".stripMargin))
+
+ List(
+ ws.receive()
+ .map { case t: Text =>
+ t.payload
+ },
+ ws.receive()
+ .map { case t: Text =>
+ t.payload
+ },
+ ws.receive()
+ .map { case t: Text =>
+ t.payload
+ })
+ })
+ .send(backend)
+ .body
+
+ Thread.sleep(100)
+
+ val jmapGuiceProbe: JmapGuiceProbe = server.getProbe(classOf[JmapGuiceProbe])
+ val emailState: String = jmapGuiceProbe.getLatestEmailState(accountId).getValue.toString
+ val mailboxState: String = jmapGuiceProbe.getLatestMailboxState(accountId).getValue.toString
+
+ val mailboxStateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Mailbox":"$mailboxState"}}}"""
+ val emailStateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Email":"$emailState"}}}"""
+
+ assertThat(response.toOption.get.asJava)
+ .hasSize(3) // email notification + mailbox notification + API response
+ .contains(mailboxStateChange, emailStateChange)
+ }
+
+ @Test
def dataTypesShouldDefaultToAll(server: GuiceJamesServer): Unit = {
val bobPath = MailboxPath.inbox(BOB)
val accountId: AccountId = AccountId.fromUsername(BOB)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/StateChange.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/StateChange.scala
index 73ab7e2..faffe49 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/StateChange.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/StateChange.scala
@@ -25,7 +25,7 @@ import org.apache.james.events.Event.EventId
import org.apache.james.jmap.core.{AccountId, State, StateChange}
object TypeName {
- val ALL: Set[TypeName] = Set(EmailTypeName, MailboxTypeName)
+ val ALL: Set[TypeName] = Set(EmailTypeName, MailboxTypeName, ThreadTypeName, IdentityTypeName, EmailSubmissionTypeName, EmailDeliveryTypeName)
}
sealed trait TypeName {
@@ -41,6 +41,21 @@ case object MailboxTypeName extends TypeName {
case object EmailTypeName extends TypeName {
override val asString: String = "Email"
}
+case object ThreadTypeName extends TypeName {
+ override val asString: String = "Thread"
+}
+case object IdentityTypeName extends TypeName {
+ override val asString: String = "Identity"
+}
+case object EmailSubmissionTypeName extends TypeName {
+ override val asString: String = "EmailSubmission"
+}
+case object EmailDeliveryTypeName extends TypeName {
+ override val asString: String = "EmailDelivery"
+}
+case object VacationResponseTypeName extends TypeName {
+ override val asString: String = "VacationResponse"
+}
case class TypeState(changes: Map[TypeName, State]) {
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 b1454c6..042d4d8 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
@@ -25,7 +25,7 @@ import java.net.URL
import eu.timepit.refined.refineV
import io.netty.handler.codec.http.HttpResponseStatus
import org.apache.james.core.Username
-import org.apache.james.jmap.change.{EmailTypeName, MailboxTypeName, TypeName, TypeState}
+import org.apache.james.jmap.change.{EmailDeliveryTypeName, EmailSubmissionTypeName, EmailTypeName, IdentityTypeName, MailboxTypeName, ThreadTypeName, TypeName, TypeState, VacationResponseTypeName}
import org.apache.james.jmap.core
import org.apache.james.jmap.core.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.core.Id.IdConstraint
@@ -189,6 +189,11 @@ object ResponseSerializer {
private implicit val typeNameReads: Reads[TypeName] = {
case JsString(MailboxTypeName.asString) => JsSuccess(MailboxTypeName)
case JsString(EmailTypeName.asString) => JsSuccess(EmailTypeName)
+ case JsString(ThreadTypeName.asString) => JsSuccess(ThreadTypeName)
+ case JsString(IdentityTypeName.asString) => JsSuccess(IdentityTypeName)
+ case JsString(EmailSubmissionTypeName.asString) => JsSuccess(EmailSubmissionTypeName)
+ case JsString(EmailDeliveryTypeName.asString) => JsSuccess(EmailDeliveryTypeName)
+ case JsString(VacationResponseTypeName.asString) => JsSuccess(VacationResponseTypeName)
case _ => JsError("Expecting a JsString as typeName")
}
private implicit val webSocketPushEnableReads: Reads[WebSocketPushEnable] = Json.reads[WebSocketPushEnable]
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org