This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch 3.9.x
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit c163c2c7f6f64d1c4729455a2c6dbcd48636ed25
Author: Benoit TELLIER <[email protected]>
AuthorDate: Mon Nov 10 11:46:56 2025 +0100

    JAMES-3728 Plug MessageIdManager::updateEmail into the JMAP layer 
(Email/set update)
---
 .../jmap/method/EmailSetUpdatePerformer.scala      | 31 +++++++++++++++++-----
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git 
a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetUpdatePerformer.scala
 
b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetUpdatePerformer.scala
index 484e2f3fb2..a4d0c21df8 100644
--- 
a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetUpdatePerformer.scala
+++ 
b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetUpdatePerformer.scala
@@ -207,13 +207,30 @@ class EmailSetUpdatePerformer @Inject() (serializer: 
EmailSetSerializer,
     if (mailboxIds.value.isEmpty) {
       
SMono.just[EmailUpdateResult](EmailUpdateFailure(EmailSet.asUnparsed(messageId),
 MessageNotFoundException(messageId)))
     } else {
-      updateFlags(messageId, update, mailboxIds, storedMetaData, session)
-        .flatMap {
-          case failure: EmailUpdateFailure => 
SMono.just[EmailUpdateResult](failure)
-          case _: EmailUpdateSuccess => updateMailboxIds(messageId, update, 
mailboxIds, session)
-        }
-        .onErrorResume(e => 
SMono.just[EmailUpdateResult](EmailUpdateFailure(EmailSet.asUnparsed(messageId),
 e)))
-        
.switchIfEmpty(SMono.just[EmailUpdateResult](EmailUpdateSuccess(messageId)))
+      if (update.update.isMailboxUpdate && update.update.isFlagUpdate) {
+        // JAMS-3728 Handling move nd flags update at once prevents data race
+        val targetIds = update.mailboxIdsTransformation.apply(mailboxIds)
+        val originalFlags: Flags = storedMetaData
+          .foldLeft[Flags](new Flags())((flags: Flags, m: 
ComposedMessageIdWithMetaData) => {
+            flags.add(m.getFlags)
+            flags
+          })
+        val newFlags = update.keywordsTransformation
+          .apply(LENIENT_KEYWORDS_FACTORY.fromFlags(originalFlags).get)
+          .asFlagsWithRecentAndDeletedFrom(originalFlags)
+        SMono(messageIdManager.updateEmail(messageId, targetIds.value.asJava, 
newFlags, FlagsUpdateMode.REPLACE, session))
+          .`then`(SMono.just[EmailUpdateResult](EmailUpdateSuccess(messageId)))
+          .onErrorResume(e => 
SMono.just[EmailUpdateResult](EmailUpdateFailure(EmailSet.asUnparsed(messageId),
 e)))
+          
.switchIfEmpty(SMono.just[EmailUpdateResult](EmailUpdateSuccess(messageId)))
+      } else {
+        updateFlags(messageId, update, mailboxIds, storedMetaData, session)
+          .flatMap {
+            case failure: EmailUpdateFailure => 
SMono.just[EmailUpdateResult](failure)
+            case _: EmailUpdateSuccess => updateMailboxIds(messageId, update, 
mailboxIds, session)
+          }
+          .onErrorResume(e => 
SMono.just[EmailUpdateResult](EmailUpdateFailure(EmailSet.asUnparsed(messageId),
 e)))
+          
.switchIfEmpty(SMono.just[EmailUpdateResult](EmailUpdateSuccess(messageId)))
+      }
     }
   }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to