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


The following commit(s) were added to refs/heads/master by this push:
     new 1f2f818c23 JAMES-4096 Rename INBOX (#2549)
1f2f818c23 is described below

commit 1f2f818c23b7ce0b676c582d8e355aabcae6978c
Author: hungphan227 <45198168+hungphan...@users.noreply.github.com>
AuthorDate: Fri Dec 6 23:49:39 2024 +0700

    JAMES-4096 Rename INBOX (#2549)
    
    Co-authored-by: hung phan <hp...@linagora.com>
---
 .../james/mailbox/store/StoreMailboxManager.java   |  41 ++--
 .../apache/james/mpt/imapmailbox/suite/Rename.java |   6 +
 .../org/apache/james/imap/scripts/RenameInbox.test |  75 ++++++
 .../contract/MailboxSetMethodContract.scala        | 269 ++++++++++++++++++++-
 .../jmap/method/MailboxSetUpdatePerformer.scala    |  71 +++---
 5 files changed, 417 insertions(+), 45 deletions(-)

diff --git 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index 86972fbd2a..4eda433a06 100644
--- 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -37,6 +37,7 @@ import org.apache.james.core.Username;
 import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeUsage;
 import org.apache.james.events.EventBus;
+import org.apache.james.mailbox.DefaultMailboxes;
 import org.apache.james.mailbox.MailboxAnnotationManager;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxPathLocker;
@@ -689,22 +690,7 @@ public class StoreMailboxManager implements MailboxManager 
{
                 resultBuilder.add(new MailboxRenamedResult(mailboxId, from, 
newMailboxPath));
                 return mailboxId;
             })
-            .then(Mono.from(locker.executeReactiveWithLockReactive(from, 
mapper.findMailboxWithPathLike(query)
-                    .concatMap(sub -> {
-                        String subOriginalName = sub.getName();
-                        String subNewName = newMailboxPath.getName() + 
subOriginalName.substring(from.getName().length());
-                        MailboxPath fromPath = new MailboxPath(from, 
subOriginalName);
-                        sub.setName(subNewName);
-                        sub.setUser(toSession.getUser());
-                        return mapper.rename(sub)
-                            .map(mailboxId -> {
-                                resultBuilder.add(new 
MailboxRenamedResult(sub.getMailboxId(), fromPath, 
sub.generateAssociatedPath()));
-                                return mailboxId;
-                            })
-                            .retryWhen(Retry.backoff(5, Duration.ofMillis(10)))
-                            .then(Mono.fromRunnable(() -> LOGGER.debug("Rename 
mailbox sub-mailbox {} to {}", subOriginalName, subNewName)));
-                    }, LOW_CONCURRENCY)
-                    .then(), MailboxPathLocker.LockType.Write)))
+            .then(Mono.from(renameSubMailboxes(newMailboxPath, toSession, 
mapper, from, query, resultBuilder)))
             .then(Mono.defer(() -> Flux.fromIterable(resultBuilder.build())
                 .concatMap(result -> 
eventBus.dispatch(EventFactory.mailboxRenamed()
                         .randomEventId()
@@ -718,6 +704,29 @@ public class StoreMailboxManager implements MailboxManager 
{
             .then(Mono.fromCallable(resultBuilder::build));
     }
 
+    private Publisher<Void> renameSubMailboxes(MailboxPath newMailboxPath, 
MailboxSession toSession, MailboxMapper mapper,
+                                               MailboxPath from, 
MailboxQuery.UserBound query, ImmutableList.Builder<MailboxRenamedResult> 
resultBuilder) {
+        if (DefaultMailboxes.INBOX.equalsIgnoreCase(from.getName())) {
+            return Mono.empty();
+        }
+        return locker.executeReactiveWithLockReactive(from, 
mapper.findMailboxWithPathLike(query)
+            .concatMap(sub -> {
+                String subOriginalName = sub.getName();
+                String subNewName = newMailboxPath.getName() + 
subOriginalName.substring(from.getName().length());
+                MailboxPath fromPath = new MailboxPath(from, subOriginalName);
+                sub.setName(subNewName);
+                sub.setUser(toSession.getUser());
+                return mapper.rename(sub)
+                    .map(mailboxId -> {
+                        resultBuilder.add(new 
MailboxRenamedResult(sub.getMailboxId(), fromPath, 
sub.generateAssociatedPath()));
+                        return mailboxId;
+                    })
+                    .retryWhen(Retry.backoff(5, Duration.ofMillis(10)))
+                    .then(Mono.fromRunnable(() -> LOGGER.debug("Rename mailbox 
sub-mailbox {} to {}", subOriginalName, subNewName)));
+            }, LOW_CONCURRENCY)
+            .then(), MailboxPathLocker.LockType.Write);
+    }
+
     @Override
     public List<MessageRange> copyMessages(MessageRange set, MailboxPath from, 
MailboxPath to, MailboxSession session) throws MailboxException {
         return MailboxReactorUtils.block(copyMessagesReactive(set, from, to, 
session).collectList());
diff --git 
a/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/Rename.java
 
b/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/Rename.java
index 6ab8d07750..e912e604a5 100644
--- 
a/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/Rename.java
+++ 
b/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/Rename.java
@@ -108,4 +108,10 @@ public abstract class Rename implements ImapTestConstants {
             .withLocale(Locale.KOREA)
             .run("RenameSelected");
     }
+
+    @Test
+    public void testRenameInbox() throws Exception {
+        simpleScriptedTestProtocol
+            .run("RenameInbox");
+    }
 }
diff --git 
a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/RenameInbox.test
 
b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/RenameInbox.test
new file mode 100644
index 0000000000..50e7998144
--- /dev/null
+++ 
b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/RenameInbox.test
@@ -0,0 +1,75 @@
+################################################################
+# Licensed to the Apache Software Foundation (ASF) under one   #
+# or more contributor license agreements.  See the NOTICE file #
+# distributed with this work for additional information        #
+# regarding copyright ownership.  The ASF licenses this file   #
+# to you under the Apache License, Version 2.0 (the            #
+# "License"); you may not use this file except in compliance   #
+# with the License.  You may obtain a copy of the License at   #
+#                                                              #
+#   http://www.apache.org/licenses/LICENSE-2.0                 #
+#                                                              #
+# Unless required by applicable law or agreed to in writing,   #
+# software distributed under the License is distributed on an  #
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       #
+# KIND, either express or implied.  See the License for the    #
+# specific language governing permissions and limitations      #
+# under the License.                                           #
+################################################################
+
+C: A0 APPEND INBOX {185+}
+C: From: Timothy Tayler <timo...@example.org>
+C: To: Samual Smith <sam...@example.org>
+C: Date: Thu, 14 Feb 2008 12:00:00 +0000 (GMT)
+C: Subject: A Simple Email
+C:
+C: This is a very simple email.
+C:
+S: A0 OK (\[.+\] )?APPEND completed\.
+
+C: A1 CREATE INBOX.child
+S: A1 OK \[MAILBOXID \(.+\)\] CREATE completed\.
+
+C: A2 RENAME INBOX testmailbox
+S: A2 OK RENAME completed\.
+
+C: A3 SELECT testmailbox
+S: \* OK \[MAILBOXID \(.+\)\] Ok
+S: \* FLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\Seen\)
+S: \* 1 EXISTS
+S: \* 1 RECENT
+S: \* OK \[UIDVALIDITY \d+\].*
+S: \* OK \[UNSEEN 1].*
+S: \* OK \[PERMANENTFLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\\Seen( 
\\\*)?\)\].*
+S: \* OK \[HIGHESTMODSEQ \d+\].*
+S: \* OK \[UIDNEXT 2\].*
+S: A3 OK \[READ-WRITE\] SELECT completed\.
+
+C: A4 SELECT INBOX
+S: \* OK \[MAILBOXID \(.+\)\] Ok
+S: \* FLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\Seen\)
+S: \* 0 EXISTS
+S: \* 0 RECENT
+S: \* OK \[UIDVALIDITY \d+\].*
+S: \* OK \[PERMANENTFLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\\Seen( 
\\\*)?\)\].*
+S: \* OK \[HIGHESTMODSEQ \d+\].*
+S: \* OK \[UIDNEXT 1\].*
+S: A4 OK \[READ-WRITE\] SELECT completed\.
+
+C: A5 SELECT INBOX.child
+S: \* OK \[MAILBOXID \(.+\)\] Ok
+S: \* FLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\Seen\)
+S: \* 0 EXISTS
+S: \* 0 RECENT
+S: \* OK \[UIDVALIDITY \d+\].*
+S: \* OK \[PERMANENTFLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\\Seen( 
\\\*)?\)\].*
+S: \* OK \[HIGHESTMODSEQ \d+\].*
+S: \* OK \[UIDNEXT 1\].*
+S: A5 OK \[READ-WRITE\] SELECT completed\.
+
+C: A6 LIST "" "*"
+S: \* LIST \(\\HasChildren\) "\." "INBOX"
+S: \* LIST \(\\HasNoChildren\) "\." "INBOX\.child"
+S: \* LIST \(\\HasNoChildren\) "\." "selected"
+S: \* LIST \(\\HasNoChildren\) "\." "testmailbox"
+S: A6 OK LIST completed\.
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 f6d96190c9..9263595755 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
@@ -37,9 +37,10 @@ import org.apache.james.jmap.http.UserCredential
 import 
org.apache.james.jmap.rfc8621.contract.Fixture.{ACCEPT_RFC8621_VERSION_HEADER, 
ACCOUNT_ID, ANDRE, BOB, BOB_PASSWORD, CEDRIC, DAVID, DOMAIN, authScheme, 
baseRequestSpecBuilder}
 import org.apache.james.jmap.rfc8621.contract.tags.CategoryTags
 import org.apache.james.jmap.{JmapGuiceProbe, MessageIdProbe}
+import org.apache.james.mailbox.DefaultMailboxes
 import org.apache.james.mailbox.MessageManager.AppendCommand
 import org.apache.james.mailbox.model.MailboxACL.{EntryKey, Right}
-import org.apache.james.mailbox.model.{MailboxACL, MailboxId, MailboxPath}
+import org.apache.james.mailbox.model.{MailboxACL, MailboxConstants, 
MailboxId, MailboxPath}
 import org.apache.james.mime4j.dom.Message
 import org.apache.james.modules.{ACLProbeImpl, MailboxProbeImpl}
 import org.apache.james.util.concurrency.ConcurrentTestRunner
@@ -3802,7 +3803,7 @@ trait MailboxSetMethodContract {
   @Test
   def updateShouldNotRenameSystemMailboxes(server: GuiceJamesServer): Unit = {
     val mailboxId: MailboxId = server.getProbe(classOf[MailboxProbeImpl])
-      .createMailbox(MailboxPath.forUser(BOB, "INBOX"))
+      .createMailbox(MailboxPath.forUser(BOB, DefaultMailboxes.DRAFTS))
     val request =
       s"""
         |{
@@ -3854,6 +3855,270 @@ trait MailboxSetMethodContract {
          |}""".stripMargin)
   }
 
+  @Test
+  def updateShouldRenameInbox(server: GuiceJamesServer): Unit = {
+    val bobPath = MailboxPath.inbox(BOB)
+    val mailboxId: MailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath)
+    server.getProbe(classOf[MailboxProbeImpl]).appendMessage(BOB.asString(), 
bobPath,
+        
AppendCommand.from(Message.Builder.of.setSubject("test").setBody("testmail", 
StandardCharsets.UTF_8).build))
+
+    val request =
+      s"""
+         |{
+         |   "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+         |   "methodCalls": [
+         |      ["Mailbox/set",
+         |          {
+         |               "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |               "update": {
+         |                 "${mailboxId.serialize}" : {
+         |                   "name": "newName"
+         |                 }
+         |               }
+         |          },
+         |   "c2"],
+         |      ["Mailbox/get",
+         |         {
+         |           "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |           "properties": ["id", "name", "totalEmails"],
+         |           "ids": ["${mailboxId.serialize}"]
+         |          },
+         |       "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
+
+    assertThatJson(response)
+      .whenIgnoringPaths("methodResponses[1][1].state", 
"methodResponses[0][1].newState", "methodResponses[0][1].oldState")
+      .isEqualTo(
+        s"""{
+           |  "sessionState": "${SESSION_STATE.value}",
+           |  "methodResponses": [
+           |    ["Mailbox/set", {
+           |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |      "updated": {
+           |        "${mailboxId.serialize}": {}
+           |      }
+           |    }, "c2"],
+           |    ["Mailbox/get", {
+           |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |      "state": "${INSTANCE.value}",
+           |      "list": [{
+           |        "id": "${mailboxId.serialize}",
+           |        "name": "newName",
+           |        "totalEmails": 1
+           |      }],
+           |      "notFound": []
+           |    }, "c2"]
+           |  ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  def renameInboxShouldCreateNewInbox(server: GuiceJamesServer): Unit = {
+    val bobPath = MailboxPath.inbox(BOB)
+    val mailboxId: MailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath)
+    server.getProbe(classOf[MailboxProbeImpl]).appendMessage(BOB.asString(), 
bobPath,
+      
AppendCommand.from(Message.Builder.of.setSubject("test").setBody("testmail", 
StandardCharsets.UTF_8).build))
+
+    val request =
+      s"""
+         |{
+         |   "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+         |   "methodCalls": [
+         |      ["Mailbox/set",
+         |          {
+         |               "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |               "update": {
+         |                 "${mailboxId.serialize}" : {
+         |                   "name": "newName"
+         |                 }
+         |               }
+         |          },
+         |   "c2"],
+         |      ["Mailbox/get",
+         |         {
+         |           "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |           "properties": ["id", "name"],
+         |           "ids": ["${mailboxId.serialize}"]
+         |          },
+         |       "c2"]
+         |   ]
+         |}
+         |""".stripMargin
+
+    `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .log().ifValidationFails()
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    val newInboxId: MailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).getMailboxId("#private", 
BOB.asString(), MailboxConstants.INBOX)
+
+    val request2 =
+      s"""
+         |{
+         |   "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+         |   "methodCalls": [
+         |      ["Mailbox/get",
+         |         {
+         |           "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |           "properties": ["id", "name", "totalEmails"],
+         |           "ids": ["${newInboxId.serialize}"]
+         |          },
+         |       "c2"]
+         |   ]
+         |}
+         |""".stripMargin
+
+    val response2 = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request2)
+    .when
+      .post
+    .`then`
+      .log().ifValidationFails()
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response2)
+      .whenIgnoringPaths("methodResponses[0][1].state", 
"methodResponses[0][1].newState", "methodResponses[0][1].oldState")
+      .isEqualTo(
+        s"""{
+           |  "sessionState": "${SESSION_STATE.value}",
+           |  "methodResponses": [
+           |    ["Mailbox/get", {
+           |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |      "state": "${INSTANCE.value}",
+           |      "list": [{
+           |        "id": "${newInboxId.serialize}",
+           |        "name": "INBOX",
+           |        "totalEmails": 0
+           |      }],
+           |      "notFound": []
+           |    }, "c2"]
+           |  ]
+           |}""".stripMargin)
+  }
+
+  @Test
+  def renameInboxShouldNotAffectSubMailboxes(server: GuiceJamesServer): Unit = 
{
+    val mailboxId: MailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.forUser(BOB,
 "INBOX"))
+    val subInboxId: MailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.forUser(BOB,
 "INBOX.subInbox"))
+
+    val request =
+      s"""
+         |{
+         |   "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+         |   "methodCalls": [
+         |      ["Mailbox/set",
+         |          {
+         |               "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |               "update": {
+         |                 "${mailboxId.serialize}" : {
+         |                   "name": "newName"
+         |                 }
+         |               }
+         |          },
+         |   "c2"],
+         |      ["Mailbox/get",
+         |         {
+         |           "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |           "properties": ["id", "name"],
+         |           "ids": ["${mailboxId.serialize}"]
+         |          },
+         |       "c2"]
+         |   ]
+         |}
+         |""".stripMargin
+
+    `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .log().ifValidationFails()
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    val newInboxId: MailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).getMailboxId("#private", 
BOB.asString(), MailboxConstants.INBOX)
+
+    val request2 =
+      s"""
+         |{
+         |   "using": [ "urn:ietf:params:jmap:core", 
"urn:ietf:params:jmap:mail" ],
+         |   "methodCalls": [
+         |      ["Mailbox/get",
+         |         {
+         |           "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |           "properties": ["id", "name", "parentId"],
+         |           "ids": ["${subInboxId.serialize}"]
+         |          },
+         |       "c2"]
+         |   ]
+         |}
+         |""".stripMargin
+
+    val response2 = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request2)
+    .when
+      .post
+    .`then`
+      .log().ifValidationFails()
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response2)
+      .whenIgnoringPaths("methodResponses[0][1].state", 
"methodResponses[0][1].newState", "methodResponses[0][1].oldState")
+      .isEqualTo(
+        s"""{
+           |  "sessionState": "${SESSION_STATE.value}",
+           |  "methodResponses": [
+           |    ["Mailbox/get", {
+           |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |      "state": "${INSTANCE.value}",
+           |      "list": [{
+           |        "id": "${subInboxId.serialize}",
+           |        "name": "subInbox",
+           |        "parentId": "${newInboxId.serialize}"
+           |      }],
+           |      "notFound": []
+           |    }, "c2"]
+           |  ]
+           |}""".stripMargin)
+  }
+
   @Test
   def destroyShouldNotRemoveSystemMailboxes(server: GuiceJamesServer): Unit = {
     val mailboxId: MailboxId = server.getProbe(classOf[MailboxProbeImpl])
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 615d96b193..7824aff7d2 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
@@ -32,7 +32,7 @@ import 
org.apache.james.mailbox.MailboxManager.{MailboxSearchFetchType, RenameOp
 import org.apache.james.mailbox.exception.{DifferentDomainException, 
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 org.apache.james.mailbox.{DefaultMailboxes, MailboxManager, 
MailboxSession, MessageManager, Role, SubscriptionManager}
 import org.apache.james.util.{AuditTrail, ReactorUtils}
 import org.slf4j.LoggerFactory
 import reactor.core.scala.publisher.{SFlux, SMono}
@@ -164,31 +164,33 @@ class MailboxSetUpdatePerformer @Inject()(serializer: 
MailboxSerializer,
                                 validatedPatch: ValidatedMailboxPatchObject,
                                 mailboxSession: MailboxSession): 
SMono[MailboxUpdateResult] = {
     if (validatedPatch.shouldUpdateMailboxPath) {
-      SMono.fromCallable[MailboxUpdateResult](() => {
-        try {
-          val mailbox = mailboxManager.getMailbox(mailboxId, mailboxSession)
-          if (isASystemMailbox(mailbox)) {
-            throw SystemMailboxChangeException(mailboxId)
-          }
-          if 
(validatedPatch.parentIdUpdate.flatMap(_.newId).contains(mailboxId)) {
-            throw LoopInMailboxGraphException(mailboxId)
-          }
-          val oldPath = mailbox.getMailboxPath
-          val newPath = applyParentIdUpdate(mailboxId, 
validatedPatch.parentIdUpdate, mailboxSession)
-            .andThen(applyNameUpdate(validatedPatch.nameUpdate, 
mailboxSession))
-            .apply(oldPath)
-          if (!oldPath.equals(newPath)) {
-            mailboxManager.renameMailbox(mailboxId,
-              newPath,
-              RenameOption.RENAME_SUBSCRIPTIONS,
-              mailboxSession)
-          }
-          MailboxUpdateSuccess(mailboxId)
-        } catch {
-          case e: Exception => MailboxUpdateFailure(unparsedMailboxId, e, 
Some(validatedPatch))
-        }
-      })
-        .subscribeOn(ReactorUtils.BLOCKING_CALL_WRAPPER)
+      SMono(mailboxManager.getMailboxReactive(mailboxId, mailboxSession))
+        .flatMap(mailbox =>
+          SMono.fromCallable[MailboxUpdateResult](() => {
+            try {
+              if (isASystemMailbox(mailbox) && 
!DefaultMailboxes.INBOX.equalsIgnoreCase(mailbox.getMailboxPath.getName)) {
+                throw SystemMailboxChangeException(mailboxId)
+              }
+              if 
(validatedPatch.parentIdUpdate.flatMap(_.newId).contains(mailboxId)) {
+                throw LoopInMailboxGraphException(mailboxId)
+              }
+              val oldPath = mailbox.getMailboxPath
+              val newPath = applyParentIdUpdate(mailboxId, 
validatedPatch.parentIdUpdate, mailboxSession)
+                .andThen(applyNameUpdate(validatedPatch.nameUpdate, 
mailboxSession))
+                .apply(oldPath)
+              if (!oldPath.equals(newPath)) {
+                mailboxManager.renameMailbox(mailboxId,
+                  newPath,
+                  RenameOption.RENAME_SUBSCRIPTIONS,
+                  mailboxSession)
+              }
+              MailboxUpdateSuccess(mailboxId)
+            } catch {
+              case e: Exception => MailboxUpdateFailure(unparsedMailboxId, e, 
Some(validatedPatch))
+            }
+          }).subscribeOn(ReactorUtils.BLOCKING_CALL_WRAPPER)
+            .flatMap(updateResult => 
createInboxIfNeeded(mailbox.getMailboxPath, mailboxSession)
+              .`then`(SMono.just(updateResult))))
     } else {
       SMono.just[MailboxUpdateResult](MailboxUpdateSuccess(mailboxId))
     }
@@ -269,6 +271,21 @@ class MailboxSetUpdatePerformer @Inject()(serializer: 
MailboxSerializer,
 
   }
 
-  private def isASystemMailbox(mailbox: MessageManager): Boolean = 
Role.from(mailbox.getMailboxPath.getName).isPresent
+  private def createInboxIfNeeded(existingPath: MailboxPath, session: 
MailboxSession): SMono[Unit] = {
+    if (!existingPath.getName.equalsIgnoreCase(DefaultMailboxes.INBOX)) {
+      return SMono.empty
+    }
+    SMono(mailboxManager.mailboxExists(existingPath, session)).flatMap(exists 
=> createInbox(exists, existingPath, session))
+  }
+
+  private def createInbox(exists: Boolean, existingPath: MailboxPath, session: 
MailboxSession): SMono[Unit] = {
+    if (exists) {
+      return SMono.empty
+    }
+    SMono(mailboxManager.createMailboxReactive(existingPath, session))
+      .`then`()
+  }
 
+  private def isASystemMailbox(mailbox: MessageManager): Boolean =
+    Role.from(mailbox.getMailboxPath.getName).isPresent
 }


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

Reply via email to