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 9b1c3888d5d6765b2aa8547c00a3e1c42b03aa5e Author: Rémi Kowalski <[email protected]> AuthorDate: Wed Jul 15 16:34:24 2020 +0200 JAMES-3098 filter properties from response --- .../contract/MailboxGetMethodContract.scala | 128 +++++++++++++++++++-- .../org/apache/james/jmap/json/Serializer.scala | 19 +-- .../scala/org/apache/james/jmap/mail/Mailbox.scala | 25 +++- .../james/jmap/method/MailboxGetMethod.scala | 2 +- .../jmap/json/MailboxGetSerializationTest.scala | 4 +- .../james/jmap/json/MailboxSerializationTest.scala | 3 +- 6 files changed, 149 insertions(+), 32 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 3f51a4b..40471f3 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 @@ -81,6 +81,21 @@ object MailboxGetMethodContract { | "c1"]] |}""".stripMargin + private val GET_ALL_MAILBOXES_REQUEST_EMPTY_PROPERTIES: String = + """{ + | "using": [ + | "urn:ietf:params:jmap:core", + | "urn:ietf:params:jmap:mail"], + | "methodCalls": [[ + | "Mailbox/get", + | { + | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6", + | "properties": [], + | "ids": null + | }, + | "c1"]] + |}""".stripMargin + private val GET_ALL_MAILBOXES_REQUEST_NAME_AND_ID_PROPERTIES: String = """{ | "using": [ @@ -156,6 +171,22 @@ object MailboxGetMethodContract { | "c1"]] |}""".stripMargin + private val GET_ALL_MAILBOXES_REQUEST_WITH_SHARES_WITH_ONLY_ID_NAME_AND_RIGHTS: String = + """{ + | "using": [ + | "urn:ietf:params:jmap:core", + | "urn:ietf:params:jmap:mail", + | "urn:apache:james:params:jmap:mail:shares"], + | "methodCalls": [[ + | "Mailbox/get", + | { + | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6", + | "properties": ["id", "name", "rights"], + | "ids": null + | }, + | "c1"]] + |}""".stripMargin + private val GET_ALL_MAILBOXES_REQUEST_WITH_BOTH: String = """{ | "using": [ @@ -436,9 +467,9 @@ trait MailboxGetMethodContract { val response: String = `given` .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) .body(GET_ALL_MAILBOXES_REQUEST) - .when + .when .post - .`then` + .`then` .statusCode(SC_OK) .contentType(JSON) .extract @@ -491,9 +522,9 @@ trait MailboxGetMethodContract { val response: String = `given` .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) .body(GET_ALL_MAILBOXES_REQUEST_NULL_PROPERTIES) - .when + .when .post - .`then` + .`then` .statusCode(SC_OK) .contentType(JSON) .extract @@ -537,7 +568,42 @@ trait MailboxGetMethodContract { |}""".stripMargin) } - @Disabled("TODO") + @Test + def getMailboxesShouldReturnIdWhenNoPropertiesRequested(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_EMPTY_PROPERTIES) + .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}" + | } + | ], + | "notFound": [] + | }, + | "c1"]] + |}""".stripMargin) + } @Test def getMailboxesShouldReturnOnlyNameAndIdWhenPropertiesRequested(server: GuiceJamesServer): Unit = { val mailboxId: String = server.getProbe(classOf[MailboxProbeImpl]) @@ -547,9 +613,9 @@ trait MailboxGetMethodContract { val response: String = `given` .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) .body(GET_ALL_MAILBOXES_REQUEST_NAME_AND_ID_PROPERTIES) - .when + .when .post - .`then` + .`then` .statusCode(SC_OK) .contentType(JSON) .extract @@ -576,7 +642,6 @@ trait MailboxGetMethodContract { |}""".stripMargin) } - @Disabled("TODO") @Test def getMailboxesShouldAlwaysReturnIdEvenIfNotRequested(server: GuiceJamesServer): Unit = { val mailboxId: String = server.getProbe(classOf[MailboxProbeImpl]) @@ -586,9 +651,9 @@ trait MailboxGetMethodContract { val response: String = `given` .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) .body(GET_ALL_MAILBOXES_REQUEST_NAME_PROPERTIES) - .when + .when .post - .`then` + .`then` .statusCode(SC_OK) .contentType(JSON) .extract @@ -617,6 +682,45 @@ trait MailboxGetMethodContract { @Disabled("TODO") @Test + def getMailboxesShouldNotIncludeNamespaceIfSharesCapabilityIsUsedAndNamespaceIsNotRequested(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_WITH_ONLY_ID_NAME_AND_RIGHTS) + .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", + | "rights": {} + | } + | ], + | "notFound": [] + | }, + | "c1"]] + |}""".stripMargin) + } + + @Test def getMailboxesShouldReturnInvalidArgumentsErrorWhenInvalidProperty(server: GuiceJamesServer): Unit = { server.getProbe(classOf[MailboxProbeImpl]) .createMailbox(MailboxPath.forUser(BOB, "custom")) @@ -624,9 +728,9 @@ trait MailboxGetMethodContract { val response: String = `given` .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) .body(GET_ALL_MAILBOXES_REQUEST_INVALID_PROPERTIES) - .when + .when .post - .`then` + .`then` .statusCode(SC_OK) .contentType(JSON) .extract 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 ad6b6b5..b31e0b5 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,8 +201,8 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) { }) } - implicit def mailboxWrites(propertiesToHide: Set[String]): Writes[Mailbox] = Json.writes[Mailbox] - .transform((o: JsObject) => JsObject(o.fields.filterNot(entry => propertiesToHide.contains(entry._1)))) + implicit def mailboxWrites(properties: Set[String]): Writes[Mailbox] = Json.writes[Mailbox] + .transform((o: JsObject) => JsObject(o.fields.filter(entry => properties.contains(entry._1)))) private implicit val idsRead: Reads[Ids] = Json.valueReads[Ids] private implicit val propertiesRead: Reads[Properties] = Json.valueReads[Properties] @@ -230,15 +230,8 @@ 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 def mailboxWritesWithFilteredProperties(properties: Option[Properties], capabilities: Set[CapabilityIdentifier]): Writes[Mailbox] = { + mailboxWrites(Mailbox.propertiesFiltered(properties, capabilities)) } private implicit def jsErrorWrites: Writes[JsError] = Json.writes[JsError] @@ -253,8 +246,8 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) { 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(mailboxGetResponse: MailboxGetResponse, properties: Option[Properties], capabilities: Set[CapabilityIdentifier]): JsValue = { + serialize(mailboxGetResponse)(mailboxWritesWithFilteredProperties(properties, capabilities)) } def serialize(errors: JsError): JsValue = Json.toJson(errors) diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Mailbox.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Mailbox.scala index 9f3cd6a..23782bb 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Mailbox.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Mailbox.scala @@ -25,6 +25,8 @@ import eu.timepit.refined.auto._ import eu.timepit.refined.collection.NonEmpty import org.apache.james.core.Username import org.apache.james.jmap.mail.MailboxName.MailboxName +import org.apache.james.jmap.model.CapabilityIdentifier +import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier import org.apache.james.jmap.model.UnsignedInt.UnsignedInt import org.apache.james.mailbox.Role import org.apache.james.mailbox.model.MailboxId @@ -142,4 +144,25 @@ case class Mailbox(id: MailboxId, def hasRole(role: Role): Boolean = this.role.contains(role) val hasSystemRole: Boolean = role.exists(_.isSystemRole) -} \ No newline at end of file +} + +object Mailbox { + def allProperties: Set[String] = Set("id", "name", "parentId", "role", "sortOrder", "totalEmails", "unreadEmails", + "totalThreads", "unreadThreads", "myRights", "isSubscribed", "namespace", "rights", "quotas") + + def propertiesFiltered(requestedProperties: Option[Properties], allowedCapabilities : Set[CapabilityIdentifier]) : Set[String] = { + val propertiesForCapabilities: Map[CapabilityIdentifier, Set[String]] = Map( + CapabilityIdentifier.JAMES_QUOTA -> Set("quotas"), + CapabilityIdentifier.JAMES_SHARES -> Set("namespace", "rights") + ) + + val propertiesToHide = propertiesForCapabilities.filterNot(entry => allowedCapabilities.contains(entry._1)) + .flatMap(_._2) + .toSet + + requestedProperties match { + case None => allProperties -- propertiesToHide + case Some(requested) => (Set("id") ++ requested.value.map(_.toString()).toSet) -- propertiesToHide + } + } +} 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 168b095..b48e7a6 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 @@ -66,7 +66,7 @@ class MailboxGetMethod @Inject() (serializer: Serializer, notFound = mailboxes.notFound)) .map(mailboxGetResponse => Invocation( methodName = methodName, - arguments = Arguments(serializer.serialize(mailboxGetResponse, capabilities).as[JsObject]), + arguments = Arguments(serializer.serialize(mailboxGetResponse, mailboxGetRequest.properties, capabilities).as[JsObject]), methodCallId = invocation.methodCallId)))) } 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 c2da125..aa22699 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,8 +42,6 @@ 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 { @@ -207,7 +205,7 @@ class MailboxGetSerializationTest extends AnyWordSpec with Matchers { |} |""".stripMargin - assertThatJson(Json.stringify(SERIALIZER.serialize(actualValue)(SERIALIZER.mailboxWrites(NO_PROPERTY_FILTERING)))).isEqualTo(expectedJson) + assertThatJson(Json.stringify(SERIALIZER.serialize(actualValue)(SERIALIZER.mailboxWrites(Mailbox.allProperties)))).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 99455a6..c3a6a1a 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 @@ -130,8 +130,7 @@ class MailboxSerializationTest extends AnyWordSpec with Matchers { |}""".stripMargin val serializer = new Serializer(new TestId.Factory) - val noPropertyFiltering: Set[String] = Set.empty - assertThatJson(Json.stringify(serializer.serialize(MAILBOX)(serializer.mailboxWrites(noPropertyFiltering)))).isEqualTo(expectedJson) + assertThatJson(Json.stringify(serializer.serialize(MAILBOX)(serializer.mailboxWrites(Mailbox.allProperties)))).isEqualTo(expectedJson) } } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
