You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2020/11/11 04:42:58 UTC

[james-project] 06/07: JAMES-3359 Allow mailbox parentId updates when have child

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 c44d4fff2ca79b3315904cafa05d6e0abfdb123f
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Nov 3 12:20:41 2020 +0700

    JAMES-3359 Allow mailbox parentId updates when have child
    
    Looping prevention is enforced by ensuring the new parentId is not one of the childs
---
 .../contract/MailboxSetMethodContract.scala        | 34 ++++++++++++----------
 .../jmap/method/MailboxSetUpdatePerformer.scala    | 19 +++++++++---
 2 files changed, 33 insertions(+), 20 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 c81aef5..3385e0d 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
@@ -5928,7 +5928,7 @@ trait MailboxSetMethodContract {
          |                "notUpdated": {
          |                    "${mailboxId.serialize}": {
          |                        "type": "invalidArguments",
-         |                        "description": "${mailboxId.serialize} parentId property cannot be updated as this mailbox has child mailboxes",
+         |                        "description": "A mailbox parentId property can not be set to itself or one of its child",
          |                        "properties": [
          |                            "parentId"
          |                        ]
@@ -7176,7 +7176,7 @@ trait MailboxSetMethodContract {
   }
 
   @Test
-  def updatingParentIdShouldFailWhenMailboxHasAChild(server: GuiceJamesServer): Unit = {
+  def updatingParentIdShouldSucceedWhenMailboxHasAChild(server: GuiceJamesServer): Unit = {
     val mailboxProbe = server.getProbe(classOf[MailboxProbeImpl])
     val mailboxId: MailboxId = mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "mailbox"))
     mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "mailbox.child"))
@@ -7217,20 +7217,22 @@ trait MailboxSetMethodContract {
 
     assertThatJson(response).isEqualTo(
       s"""{
-         |  "sessionState": "75128aab4b1b",
-         |  "methodResponses": [
-         |    ["Mailbox/set", {
-         |      "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
-         |      "newState": "000001",
-         |      "notUpdated": {
-         |        "${mailboxId.serialize}": {
-         |          "type": "invalidArguments",
-         |          "description": "${mailboxId.serialize} parentId property cannot be updated as this mailbox has child mailboxes",
-         |          "properties": ["parentId"]
-         |        }
-         |      }
-         |    }, "c1"]
-         |  ]
+         |    "sessionState": "75128aab4b1b",
+         |    "methodResponses": [
+         |        [
+         |            "Mailbox/set",
+         |            {
+         |                "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |                "newState": "000001",
+         |                "updated": {
+         |                    "${mailboxId.serialize}": {
+         |
+         |                    }
+         |                }
+         |            },
+         |            "c1"
+         |        ]
+         |    ]
          |}""".stripMargin)
   }
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetUpdatePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetUpdatePerformer.scala
index 176324f..f208989 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetUpdatePerformer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetUpdatePerformer.scala
@@ -28,8 +28,9 @@ import org.apache.james.jmap.json.MailboxSerializer
 import org.apache.james.jmap.mail.MailboxGet.UnparsedMailboxId
 import org.apache.james.jmap.mail.{InvalidPatchException, InvalidPropertyException, InvalidUpdateException, MailboxGet, MailboxPatchObject, MailboxSetRequest, MailboxSetResponse, MailboxUpdateResponse, NameUpdate, ParentIdUpdate, ServerSetPropertyException, UnsupportedPropertyUpdatedException, ValidatedMailboxPatchObject}
 import org.apache.james.jmap.method.MailboxSetUpdatePerformer.{MailboxUpdateFailure, MailboxUpdateResult, MailboxUpdateResults, MailboxUpdateSuccess}
-import org.apache.james.mailbox.MailboxManager.RenameOption
+import org.apache.james.mailbox.MailboxManager.{MailboxSearchFetchType, RenameOption}
 import org.apache.james.mailbox.exception.{InsufficientRightsException, MailboxExistsException, MailboxNameException, MailboxNotFoundException}
+import org.apache.james.mailbox.model.search.{MailboxQuery, PrefixedWildcard}
 import org.apache.james.mailbox.model.{MailboxId, MailboxPath}
 import org.apache.james.mailbox.{MailboxManager, MailboxSession, MessageManager, Role, SubscriptionManager}
 import reactor.core.scala.publisher.{SFlux, SMono}
@@ -58,7 +59,6 @@ object MailboxSetUpdatePerformer {
       case e: SystemMailboxChangeException => SetError.invalidArguments(SetErrorDescription("Invalid change to a system mailbox"), filter(Properties("name", "parentId")))
       case e: LoopInMailboxGraphException => SetError.invalidArguments(SetErrorDescription("A mailbox parentId property can not be set to itself or one of its child"), Some(Properties("parentId")))
       case e: InsufficientRightsException => SetError.invalidArguments(SetErrorDescription("Invalid change to a delegated mailbox"))
-      case e: MailboxHasChildException => SetError.invalidArguments(SetErrorDescription(s"${e.mailboxId.serialize()} parentId property cannot be updated as this mailbox has child mailboxes"), Some(Properties("parentId")))
       case e: IllegalArgumentException => SetError.invalidArguments(SetErrorDescription(e.getMessage), None)
       case _ => SetError.serverFail(SetErrorDescription(exception.getMessage))
     }
@@ -184,8 +184,19 @@ class MailboxSetUpdatePerformer @Inject()(serializer: MailboxSerializer,
       val currentName = originalPath.getName(mailboxSession.getPathDelimiter)
       parentIdUpdate.newId
         .map(id => {
-          if (mailboxManager.hasChildren(originalPath, mailboxSession)) {
-            throw MailboxHasChildException(mailboxId)
+          val createsALoop = SFlux.fromPublisher(
+            mailboxManager.search(MailboxQuery.builder()
+              .userAndNamespaceFrom(originalPath)
+              .expression(new PrefixedWildcard(originalPath.getName + mailboxSession.getPathDelimiter))
+              .build(),
+              MailboxSearchFetchType.Minimal,
+              mailboxSession))
+            .filter(child => child.getId.equals(id))
+            .hasElements
+            .block()
+
+          if (createsALoop) {
+            throw LoopInMailboxGraphException(mailboxId)
           }
           val parentPath = mailboxManager.getMailbox(id, mailboxSession).getMailboxPath
           parentPath.child(currentName, mailboxSession.getPathDelimiter)


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