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 5aaedd129fd3c358701cd4d494b3f910ace033ad Author: Benoit Tellier <[email protected]> AuthorDate: Fri Aug 14 10:51:13 2020 +0700 JAMES-3356 Allow the use of Mailbox CreationId for parentId --- .../contract/MailboxSetMethodContract.scala | 120 ++++++++++++++++++++- .../org/apache/james/jmap/mail/MailboxSet.scala | 2 +- .../james/jmap/method/MailboxSetMethod.scala | 35 +++--- 3 files changed, 139 insertions(+), 18 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/MailboxSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala index becc612..28bd5fd 100644 --- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala +++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala @@ -219,7 +219,7 @@ trait MailboxSetMethodContract { | "notCreated": { | "C42": { | "type": "invalidArguments", - | "description": "'/parentId' property in mailbox object is not valid" + | "description": "'/parentId' property in mailbox object is not valid: Predicate isEmpty() did not fail." | } | } | }, @@ -1195,6 +1195,124 @@ trait MailboxSetMethodContract { } @Test + def createParentIdShouldAcceptCreationIdsWithinTheSameRequest(server: GuiceJamesServer): Unit = { + val request = + s""" + |{ + | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ], + | "methodCalls": [ + | ["Mailbox/set", + | { + | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6", + | "create": { + | "C42": { + | "name": "parent" + | } + | } + | }, + | "c1"], + | ["Mailbox/set", + | { + | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6", + | "create": { + | "C43": { + | "name": "child", + | "parentId": "#C42" + | } + | } + | }, + | "c2"] + | ] + |} + |""".stripMargin + + val response = `given` + .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) + .body(request) + .when + .post + .`then` + .log().ifValidationFails() + .statusCode(SC_OK) + .contentType(JSON) + .extract + .body + .asString + + val parentId: String = server.getProbe(classOf[MailboxProbeImpl]) + .getMailboxId("#private", BOB.asString(), "parent") + .serialize() + val childId: String = server.getProbe(classOf[MailboxProbeImpl]) + .getMailboxId("#private", BOB.asString(), "parent.child") + .serialize() + + assertThatJson(response).isEqualTo( + s"""{ + | "sessionState": "75128aab4b1b", + | "methodResponses": [ + | [ + | "Mailbox/set", + | { + | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6", + | "newState": "000001", + | "created": { + | "C42": { + | "id": "$parentId", + | "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": true + | } + | } + | }, + | "c1" + | ], + | [ + | "Mailbox/set", + | { + | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6", + | "newState": "000001", + | "created": { + | "C43": { + | "id": "$childId", + | "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": true + | } + | } + | }, + | "c2" + | ] + | ] + |}""".stripMargin) + } + + @Test def creationIdReferencesShouldFailWhenWrongOrder(server: GuiceJamesServer): Unit = { val request = s""" diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala index 2b2fc13..fdf2d18 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala @@ -43,7 +43,7 @@ object MailboxSetRequest { } case class RemoveEmailsOnDestroy(value: Boolean) extends AnyVal -case class MailboxCreationRequest(name: MailboxName, parentId: Option[MailboxId]) +case class MailboxCreationRequest(name: MailboxName, parentId: Option[UnparsedMailboxId]) case class MailboxPatchObject(value: Map[String, JsObject]) diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala index 94b64b2..61f8452 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala @@ -114,19 +114,6 @@ class MailboxSetMethod @Inject()(serializer: Serializer, })) } - def parseCreate(jsObject: JsObject): Either[MailboxCreationParseException, MailboxCreationRequest] = - Json.fromJson(jsObject)(serializer.mailboxCreationRequest) match { - case JsSuccess(creationRequest, _) => Right(creationRequest) - case JsError(errors) => Left(MailboxCreationParseException(mailboxSetError(errors))) - } - - private def mailboxSetError(errors: collection.Seq[(JsPath, collection.Seq[JsonValidationError])]): MailboxSetError = - errors.head match { - case (path, Seq()) => MailboxSetError.invalidArgument(Some(SetErrorDescription(s"'$path' property in mailbox object is not valid")), None) - case (path, Seq(JsonValidationError(Seq("error.path.missing")))) => MailboxSetError("invalidArguments", Some(SetErrorDescription(s"Missing '$path' property in mailbox object")), None) - case (path, _) => MailboxSetError.invalidArgument(Some(SetErrorDescription(s"Unknown error on property '$path'")), None) - } - private def deleteMailboxes(mailboxSession: MailboxSession, mailboxSetRequest: MailboxSetRequest, processingContext: ProcessingContext): SMono[DeletionResults] = { SFlux.fromIterable(mailboxSetRequest.destroy.getOrElse(Seq())) .flatMap(id => delete(mailboxSession, processingContext, id) @@ -176,11 +163,25 @@ class MailboxSetMethod @Inject()(serializer: Serializer, jsObject: JsObject, processingContext: ProcessingContext): CreationResult = { parseCreate(jsObject) - .flatMap(mailboxCreationRequest => resolvePath(mailboxSession, mailboxCreationRequest)) + .flatMap(mailboxCreationRequest => resolvePath(mailboxSession, mailboxCreationRequest, processingContext)) .map(path => createMailbox(mailboxSession, mailboxCreationId, processingContext, path)) .fold(e => CreationFailure(mailboxCreationId, e), r => r) } + private def parseCreate(jsObject: JsObject): Either[MailboxCreationParseException, MailboxCreationRequest] = + Json.fromJson(jsObject)(serializer.mailboxCreationRequest) match { + case JsSuccess(creationRequest, _) => Right(creationRequest) + case JsError(errors) => Left(MailboxCreationParseException(mailboxSetError(errors))) + } + + private def mailboxSetError(errors: collection.Seq[(JsPath, collection.Seq[JsonValidationError])]): MailboxSetError = + errors.head match { + case (path, Seq()) => MailboxSetError.invalidArgument(Some(SetErrorDescription(s"'$path' property in mailbox object is not valid")), None) + case (path, Seq(JsonValidationError(Seq("error.path.missing")))) => MailboxSetError("invalidArguments", Some(SetErrorDescription(s"Missing '$path' property in mailbox object")), None) + case (path, Seq(JsonValidationError(Seq(message)))) => MailboxSetError("invalidArguments", Some(SetErrorDescription(s"'$path' property in mailbox object is not valid: $message")), None) + case (path, _) => MailboxSetError.invalidArgument(Some(SetErrorDescription(s"Unknown error on property '$path'")), None) + } + private def createMailbox(mailboxSession: MailboxSession, mailboxCreationId: MailboxCreationId, processingContext: ProcessingContext, @@ -207,9 +208,11 @@ class MailboxSetMethod @Inject()(serializer: Serializer, } private def resolvePath(mailboxSession: MailboxSession, - mailboxCreationRequest: MailboxCreationRequest): Either[Exception, MailboxPath] = { + mailboxCreationRequest: MailboxCreationRequest, + processingContext: ProcessingContext): Either[Exception, MailboxPath] = { mailboxCreationRequest.parentId - .map(parentId => for { + .map(maybeParentId => for { + parentId <- processingContext.resolveMailboxId(maybeParentId, mailboxIdFactory) parentPath <- retrievePath(parentId, mailboxSession) } yield { parentPath.child(mailboxCreationRequest.name, mailboxSession.getPathDelimiter) --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
