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 73d99ac5b2dea05849417d9a1e5535a594378a5e
Author: TungTV <vtt...@linagora.com>
AuthorDate: Fri Sep 13 14:49:38 2024 +0700

    JAMES-4071 - Task fix inconsistencies mailbox flags: messagedeleted, 
mailboxRecents
---
 .../SolveMailboxFlagInconsistenciesService.java    | 181 +++++++++++++++++
 ...nconsistenciesTaskAdditionalInformationDTO.java |  67 +++++++
 .../SolveMailboxFlagInconsistenciesTaskDTO.java    |  49 +++++
 .../task/SolveMailboxFlagInconsistencyTask.java    |  85 ++++++++
 ...SolveMailboxFlagInconsistenciesServiceTest.java | 220 +++++++++++++++++++++
 ...lboxFlagInconsistencyTaskSerializationTest.java |  65 ++++++
 ...assandraConsistencyTaskSerializationModule.java |  20 ++
 .../webadmin/InconsistencySolvingRoutesModule.java |  33 ++++
 .../rabbitmq/ConsistencyTasksIntegrationTest.java  |  80 ++++++++
 ...MessageDeletedInconsistenciesRequestToTask.java |  42 ++++
 ...eMessageRecentInconsistenciesRequestToTask.java |  42 ++++
 11 files changed, 884 insertions(+)

diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesService.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesService.java
new file mode 100644
index 0000000000..1cf8d3b614
--- /dev/null
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesService.java
@@ -0,0 +1,181 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.task;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Predicate;
+
+import jakarta.inject.Inject;
+import jakarta.mail.Flags;
+
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxRecentsDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageMetadata;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.task.Task;
+import org.apache.james.util.streams.Limit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+import reactor.core.publisher.Mono;
+
+public class SolveMailboxFlagInconsistenciesService {
+
+    public enum TargetFlag {
+        RECENT,
+        DELETED;
+
+        public static TargetFlag from(String value) {
+            return TargetFlag.valueOf(value);
+        }
+    }
+
+    public record Context(AtomicLong processedMailboxEntries,
+                          ConcurrentLinkedDeque<CassandraId> errors) {
+
+        record Snapshot(long processedMailboxEntries, 
ImmutableList<CassandraId> errors) {
+        }
+
+        public Context() {
+            this(new AtomicLong(0), new ConcurrentLinkedDeque<>());
+        }
+
+        void incrementProcessedMailboxEntries() {
+            processedMailboxEntries.incrementAndGet();
+        }
+
+        void addError(CassandraId cassandraId) {
+            errors.add(cassandraId);
+        }
+
+        Snapshot snapshot() {
+            return new Snapshot(processedMailboxEntries.get(), 
ImmutableList.copyOf(errors));
+        }
+    }
+
+    public interface SolveMessageFlagInconsistencyStrategy {
+        Predicate<CassandraMessageMetadata> filterOutFlagInconsistencies();
+
+        Mono<Void> removeAllByMailboxId(CassandraId cassandraId);
+
+        Mono<Void> addEntry(CassandraId cassandraId, List<MessageUid> uids);
+
+        TargetFlag targetFlag();
+    }
+
+    public record 
SolveMailboxDeletedFlagInconsistenciesStrategy(CassandraDeletedMessageDAO 
deletedMessageDAO) implements SolveMessageFlagInconsistencyStrategy {
+        @Override
+        public Predicate<CassandraMessageMetadata> 
filterOutFlagInconsistencies() {
+            return metaData -> 
metaData.getComposedMessageId().getFlags().contains(Flags.Flag.DELETED);
+        }
+
+        @Override
+        public Mono<Void> removeAllByMailboxId(CassandraId cassandraId) {
+            return deletedMessageDAO.removeAll(cassandraId);
+        }
+
+        @Override
+        public Mono<Void> addEntry(CassandraId cassandraId, List<MessageUid> 
uids) {
+            return deletedMessageDAO.addDeleted(cassandraId, uids);
+        }
+
+        @Override
+        public TargetFlag targetFlag() {
+            return TargetFlag.DELETED;
+        }
+    }
+
+    public record 
SoleMailboxRecentFlagInconsistenciesStrategy(CassandraMailboxRecentsDAO 
mailboxRecentDAO) implements SolveMessageFlagInconsistencyStrategy {
+        @Override
+        public Predicate<CassandraMessageMetadata> 
filterOutFlagInconsistencies() {
+            return metaData -> 
metaData.getComposedMessageId().getFlags().contains(Flags.Flag.RECENT);
+        }
+
+        @Override
+        public Mono<Void> removeAllByMailboxId(CassandraId cassandraId) {
+            return mailboxRecentDAO.delete(cassandraId);
+        }
+
+        @Override
+        public Mono<Void> addEntry(CassandraId cassandraId, List<MessageUid> 
uids) {
+            return mailboxRecentDAO.addToRecent(cassandraId, uids);
+        }
+
+        @Override
+        public TargetFlag targetFlag() {
+            return TargetFlag.RECENT;
+        }
+    }
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(SolveMailboxFlagInconsistenciesService.class);
+
+    private final Set<SolveMessageFlagInconsistencyStrategy> 
fixInconsistenciesStrategies;
+    private final CassandraMessageIdDAO messageIdDAO;
+    private final CassandraMailboxDAO mailboxDAO;
+
+    @Inject
+    public 
SolveMailboxFlagInconsistenciesService(Set<SolveMessageFlagInconsistencyStrategy>
 fixInconsistenciesStrategies,
+                                                  CassandraMessageIdDAO 
messageIdDAO,
+                                                  CassandraMailboxDAO 
mailboxDAO) {
+        this.messageIdDAO = messageIdDAO;
+        this.fixInconsistenciesStrategies = fixInconsistenciesStrategies;
+        this.mailboxDAO = mailboxDAO;
+    }
+
+    public Mono<Task.Result> fixInconsistencies(Context context, TargetFlag 
targetFlag) {
+        SolveMessageFlagInconsistencyStrategy fixInconsistencyStrategy = 
getFixInconsistencyStrategy(targetFlag);
+        return mailboxDAO.retrieveAllMailboxes()
+            .concatMap(mailbox -> 
fixDeletedMessagesInconsistencyPerMailbox(fixInconsistencyStrategy, 
(CassandraId) mailbox.getMailboxId(), context)
+                .doOnNext(any -> context.incrementProcessedMailboxEntries()))
+            .reduce(Task.Result.COMPLETED, Task::combine);
+    }
+
+    private Mono<Task.Result> 
fixDeletedMessagesInconsistencyPerMailbox(SolveMessageFlagInconsistencyStrategy 
fixInconsistenciesStrategy, CassandraId cassandraId, Context context) {
+        return fixInconsistenciesStrategy.removeAllByMailboxId(cassandraId)
+            .then(messageIdDAO.retrieveMessages(cassandraId, 
MessageRange.all(), Limit.unlimited())
+                
.filter(fixInconsistenciesStrategy.filterOutFlagInconsistencies())
+                .map(metadata -> 
metadata.getComposedMessageId().getComposedMessageId().getUid())
+                .collectList()
+                .filter(uids -> !uids.isEmpty())
+                .flatMap(uids -> 
fixInconsistenciesStrategy.addEntry(cassandraId, uids)))
+            .thenReturn(Task.Result.COMPLETED)
+            .onErrorResume(e -> {
+                LOGGER.error("Error while fixing inconsistencies for mailbox 
{}", cassandraId, e);
+                context.addError(cassandraId);
+                return Mono.just(Task.Result.PARTIAL);
+            });
+    }
+
+    private SolveMessageFlagInconsistencyStrategy 
getFixInconsistencyStrategy(TargetFlag targetFlag) {
+        return fixInconsistenciesStrategies.stream()
+            .filter(strategy -> strategy.targetFlag() == targetFlag)
+            .findFirst()
+            .orElseThrow(() -> new IllegalArgumentException("No strategy found 
for " + targetFlag));
+    }
+}
diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO.java
new file mode 100644
index 0000000000..44cf6dce89
--- /dev/null
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO.java
@@ -0,0 +1,67 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.task;
+
+import java.time.Instant;
+
+import org.apache.james.json.DTOModule;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistencyTask.Details;
+import org.apache.james.server.task.json.dto.AdditionalInformationDTO;
+import org.apache.james.server.task.json.dto.AdditionalInformationDTOModule;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.ImmutableList;
+
+public record SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO(
+    @JsonProperty("timestamp") Instant timestamp,
+    @JsonProperty("type") String type,
+    @JsonProperty("processedMailboxEntries") long processedMailboxEntries,
+    @JsonProperty("errors") ImmutableList<String> errors,
+    @JsonProperty("targetFlag") String targetFlag) implements 
AdditionalInformationDTO {
+
+
+    public static AdditionalInformationDTOModule<Details, 
SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO> module() {
+        return DTOModule.forDomainObject(Details.class)
+            
.convertToDTO(SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO.class)
+            
.toDomainObjectConverter(SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO::toDomainObject)
+            .toDTOConverter((details, typeAsObject) -> new 
SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO(
+                details.timestamp(),
+                typeAsObject,
+                details.processedMailboxEntries(),
+                details.errors(),
+                details.targetFlag()))
+            .typeName(SolveMailboxFlagInconsistencyTask.TASK_TYPE.asString())
+            .withFactory(AdditionalInformationDTOModule::new);
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+
+    @Override
+    public Instant getTimestamp() {
+        return timestamp;
+    }
+
+    private Details toDomainObject() {
+        return new Details(timestamp, processedMailboxEntries, errors, 
targetFlag);
+    }
+}
diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesTaskDTO.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesTaskDTO.java
new file mode 100644
index 0000000000..d0776edeb4
--- /dev/null
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesTaskDTO.java
@@ -0,0 +1,49 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.task;
+
+import org.apache.james.json.DTOModule;
+import org.apache.james.server.task.json.dto.TaskDTO;
+import org.apache.james.server.task.json.dto.TaskDTOModule;
+import org.apache.james.task.TaskType;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public record SolveMailboxFlagInconsistenciesTaskDTO(@JsonProperty("type") 
String type,
+                                                     @JsonProperty("flagName") 
String flagName) implements TaskDTO {
+
+    public static final String TYPE = "solve-mailbox-flag-inconsistencies";
+    public static final TaskType TASK_TYPE = TaskType.of(TYPE);
+
+    public static TaskDTOModule<SolveMailboxFlagInconsistencyTask, 
SolveMailboxFlagInconsistenciesTaskDTO> 
module(SolveMailboxFlagInconsistenciesService 
solveMailboxFlagInconsistenciesService) {
+        return DTOModule
+            .forDomainObject(SolveMailboxFlagInconsistencyTask.class)
+            .convertToDTO(SolveMailboxFlagInconsistenciesTaskDTO.class)
+            .toDomainObjectConverter(dto -> new 
SolveMailboxFlagInconsistencyTask(solveMailboxFlagInconsistenciesService, 
dto.flagName()))
+            .toDTOConverter((task, type) -> new 
SolveMailboxFlagInconsistenciesTaskDTO(type, task.targetFlag()))
+            .typeName(TYPE)
+            .withFactory(TaskDTOModule::new);
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+}
diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistencyTask.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistencyTask.java
new file mode 100644
index 0000000000..49dbc730d2
--- /dev/null
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistencyTask.java
@@ -0,0 +1,85 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.task;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.util.Optional;
+
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService.Context;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService.TargetFlag;
+import org.apache.james.task.Task;
+import org.apache.james.task.TaskExecutionDetails;
+import org.apache.james.task.TaskType;
+
+import com.google.common.collect.ImmutableList;
+
+public class SolveMailboxFlagInconsistencyTask implements Task {
+
+    public record Details(Instant timestamp,
+                          long processedMailboxEntries,
+                          ImmutableList<String> errors,
+                          String targetFlag) implements 
TaskExecutionDetails.AdditionalInformation {
+    }
+
+    public static final String TYPE = "solve-mailbox-flag-inconsistencies";
+    public static final TaskType TASK_TYPE = TaskType.of(TYPE);
+
+    public 
SolveMailboxFlagInconsistencyTask(SolveMailboxFlagInconsistenciesService 
service, String targetFlag) {
+        this(service, Optional.ofNullable(TargetFlag.from(targetFlag))
+            .orElseThrow(() -> new IllegalArgumentException("Invalid target 
flag: " + targetFlag)));
+    }
+
+    public 
SolveMailboxFlagInconsistencyTask(SolveMailboxFlagInconsistenciesService 
service, TargetFlag targetFlag) {
+        this.context = new Context();
+        this.service = service;
+        this.targetFlag = targetFlag;
+    }
+
+    private final Context context;
+    private final SolveMailboxFlagInconsistenciesService service;
+    private final TargetFlag targetFlag;
+
+    @Override
+    public Result run() throws InterruptedException {
+        return service.fixInconsistencies(context, targetFlag).block();
+    }
+
+    @Override
+    public TaskType type() {
+        return TASK_TYPE;
+    }
+
+    @Override
+    public Optional<TaskExecutionDetails.AdditionalInformation> details() {
+        Context.Snapshot snapshot = context.snapshot();
+
+        return Optional.of(new Details(Clock.systemUTC().instant(),
+            snapshot.processedMailboxEntries(),
+            ImmutableList.copyOf(snapshot.errors().stream()
+                .map(CassandraId::serialize).toList()),
+                targetFlag.name()));
+    }
+
+    public String targetFlag() {
+        return targetFlag.name();
+    }
+}
diff --git 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesServiceTest.java
 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesServiceTest.java
new file mode 100644
index 0000000000..3d568fba6f
--- /dev/null
+++ 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistenciesServiceTest.java
@@ -0,0 +1,220 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.task;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Date;
+import java.util.Optional;
+import java.util.Set;
+
+import jakarta.mail.Flags;
+
+import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.backends.cassandra.components.CassandraModule;
+import 
org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
+import org.apache.james.blob.api.PlainBlobId;
+import org.apache.james.core.Username;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.ModSeq;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageMetadata;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService.Context;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService.SolveMailboxDeletedFlagInconsistenciesStrategy;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService.TargetFlag;
+import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
+import 
org.apache.james.mailbox.cassandra.modules.CassandraDeletedMessageModule;
+import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
+import org.apache.james.mailbox.cassandra.modules.CassandraMessageModule;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
+import org.apache.james.mailbox.model.Mailbox;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.ThreadId;
+import org.apache.james.mailbox.model.UidValidity;
+import org.apache.james.task.Task;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+class SolveMailboxFlagInconsistenciesServiceTest {
+    private static final UidValidity UID_VALIDITY_1 = UidValidity.of(145);
+    private static final Username USER = Username.of("user");
+    private static final MailboxPath MAILBOX_PATH = MailboxPath.forUser(USER, 
"abc");
+    private static final CassandraId CASSANDRA_ID_1 = CassandraId.timeBased();
+    private static final MessageUid MESSAGE_UID_1 = MessageUid.of(1);
+    private static final MessageUid MESSAGE_UID_2 = MessageUid.of(2);
+    private static final Mailbox MAILBOX = new Mailbox(MAILBOX_PATH, 
UID_VALIDITY_1, CASSANDRA_ID_1);
+    private static final CassandraId CASSANDRA_ID_2 = CassandraId.timeBased();
+    private static final Mailbox MAILBOX_2 = new Mailbox(MAILBOX_PATH, 
UID_VALIDITY_1, CASSANDRA_ID_2);
+    private static final PlainBlobId HEADER_BLOB_ID_1 = new 
PlainBlobId.Factory().of("abc");
+    private static final CassandraMessageId MESSAGE_ID_1 = new 
CassandraMessageId.Factory().fromString("d2bee791-7e63-11ea-883c-95b84008f979");
+    private static final CassandraMessageId MESSAGE_ID_2 = new 
CassandraMessageId.Factory().fromString("eeeeeeee-7e63-11ea-883c-95b84008f979");
+
+
+    @RegisterExtension
+    static CassandraClusterExtension cassandraCluster = new 
CassandraClusterExtension(
+        CassandraModule.aggregateModules(
+            CassandraSchemaVersionModule.MODULE,
+            CassandraDeletedMessageModule.MODULE,
+            CassandraMessageModule.MODULE,
+            CassandraMailboxModule.MODULE,
+            CassandraAclModule.MODULE));
+
+    SolveMailboxFlagInconsistenciesService testee;
+    CassandraMailboxDAO mailboxDAO;
+    CassandraMessageIdDAO messageIdDAO;
+    CassandraDeletedMessageDAO deletedMessageDAO;
+
+    @BeforeEach
+    void setUp(CassandraCluster cassandra) {
+        messageIdDAO = new CassandraMessageIdDAO(cassandra.getConf(), new 
PlainBlobId.Factory());
+        deletedMessageDAO = new 
CassandraDeletedMessageDAO(cassandra.getConf());
+        mailboxDAO = new CassandraMailboxDAO(
+            cassandra.getConf(),
+            cassandra.getTypesProvider());
+
+        SolveMailboxDeletedFlagInconsistenciesStrategy inconsistenciesStrategy 
= new SolveMailboxDeletedFlagInconsistenciesStrategy(deletedMessageDAO);
+        testee = new 
SolveMailboxFlagInconsistenciesService(Set.of(inconsistenciesStrategy), 
messageIdDAO, mailboxDAO);
+    }
+
+    @Test
+    void fixInconsistenciesShouldReturnCompletedWhenNoData() {
+        assertThat(testee.fixInconsistencies(new Context(), 
TargetFlag.DELETED).block())
+            .isEqualTo(Task.Result.COMPLETED);
+    }
+
+    @Test
+    void fixMessageInconsistenciesShouldReturnCompletedWhenConsistentData() {
+        MessageUid messageUid = MessageUid.of(1);
+        CassandraMessageId messageId1 = new 
CassandraMessageId.Factory().generate();
+
+        mailboxDAO.save(MAILBOX).block();
+        messageIdDAO.insert(CassandraMessageMetadata.builder()
+                .ids(ComposedMessageIdWithMetaData.builder()
+                    .composedMessageId(new ComposedMessageId(CASSANDRA_ID_1, 
messageId1, messageUid))
+                    .flags(new Flags(Flags.Flag.DELETED))
+                    .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId1))
+                    .build())
+                .internalDate(new Date())
+                .bodyStartOctet(18L)
+                .headerContent(Optional.of(HEADER_BLOB_ID_1))
+                .size(36L)
+                .build())
+            .block();
+
+        deletedMessageDAO.addDeleted(CASSANDRA_ID_1, messageUid).block();
+
+        Context context = new Context();
+        assertThat(testee.fixInconsistencies(context, 
TargetFlag.DELETED).block())
+            .isEqualTo(Task.Result.COMPLETED);
+
+        assertThat(context.snapshot().processedMailboxEntries()).isEqualTo(1);
+    }
+
+    @Test
+    void fixMessageInconsistenciesShouldFixInconsistency() {
+        // Given inconsistent data
+        mailboxDAO.save(MAILBOX).block();
+        messageIdDAO.insert(CassandraMessageMetadata.builder()
+                .ids(ComposedMessageIdWithMetaData.builder()
+                    .composedMessageId(new ComposedMessageId(CASSANDRA_ID_1, 
MESSAGE_ID_1, MESSAGE_UID_1))
+                    .flags(new Flags(Flags.Flag.DELETED))
+                    .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(MESSAGE_ID_1))
+                    .build())
+                .internalDate(new Date())
+                .bodyStartOctet(18L)
+                .headerContent(Optional.of(HEADER_BLOB_ID_1))
+                .size(36L)
+                .build())
+            .block();
+
+        deletedMessageDAO.addDeleted(CASSANDRA_ID_1, MESSAGE_UID_2).block();
+
+        // When fixing inconsistencies
+        assertThat(testee.fixInconsistencies(new Context(), 
TargetFlag.DELETED).block())
+            .isEqualTo(Task.Result.COMPLETED);
+
+        // Then the inconsistency should be fixed
+        // CASSANDRA_ID_1 - MESSAGE_UID_2 should be removed
+        // CASSANDRA_ID_1 - MESSAGE_UID_1 should be added
+        assertThat(deletedMessageDAO.retrieveDeletedMessage(CASSANDRA_ID_1, 
MessageRange.all()).collectList().block())
+            .contains(MESSAGE_UID_1);
+    }
+
+    @Test
+    void fixInconsistenciesShouldWorkOnSeveralMailbox() {
+        mailboxDAO.save(MAILBOX).block();
+        mailboxDAO.save(MAILBOX_2).block();
+
+        messageIdDAO.insert(CassandraMessageMetadata.builder()
+                .ids(ComposedMessageIdWithMetaData.builder()
+                    .composedMessageId(new ComposedMessageId(CASSANDRA_ID_1, 
MESSAGE_ID_1, MESSAGE_UID_1))
+                    .flags(new Flags(Flags.Flag.DELETED))
+                    .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(MESSAGE_ID_1))
+                    .build())
+                .internalDate(new Date())
+                .bodyStartOctet(18L)
+                .headerContent(Optional.of(HEADER_BLOB_ID_1))
+                .size(36L)
+                .build())
+            .block();
+
+        messageIdDAO.insert(CassandraMessageMetadata.builder()
+                .ids(ComposedMessageIdWithMetaData.builder()
+                    .composedMessageId(new ComposedMessageId(CASSANDRA_ID_2, 
MESSAGE_ID_2, MESSAGE_UID_2))
+                    .flags(new Flags(Flags.Flag.DELETED))
+                    .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(MESSAGE_ID_2))
+                    .build())
+                .internalDate(new Date())
+                .bodyStartOctet(18L)
+                .headerContent(Optional.of(HEADER_BLOB_ID_1))
+                .size(36L)
+                .build())
+            .block();
+
+        MessageUid messageUid3 = MessageUid.of(3);
+        deletedMessageDAO.addDeleted(CASSANDRA_ID_1, messageUid3).block();
+        deletedMessageDAO.addDeleted(CASSANDRA_ID_2, MESSAGE_UID_2).block();
+
+        // When fixing inconsistencies
+        assertThat(testee.fixInconsistencies(new Context(), 
TargetFlag.DELETED).block())
+            .isEqualTo(Task.Result.COMPLETED);
+
+        // Then the inconsistency should be fixed
+        // CASSANDRA_ID_1 - messageUid3 should be removed
+        // CASSANDRA_ID_1 - messageUid1 should be added
+        // CASSANDRA_ID_2 - messageUid2 should be kept
+        assertThat(deletedMessageDAO.retrieveDeletedMessage(CASSANDRA_ID_1, 
MessageRange.all()).collectList().block())
+            .contains(MESSAGE_UID_1);
+        assertThat(deletedMessageDAO.retrieveDeletedMessage(CASSANDRA_ID_2, 
MessageRange.all()).collectList().block())
+            .contains(MESSAGE_UID_2);
+    }
+}
\ No newline at end of file
diff --git 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistencyTaskSerializationTest.java
 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistencyTaskSerializationTest.java
new file mode 100644
index 0000000000..6c4305695a
--- /dev/null
+++ 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMailboxFlagInconsistencyTaskSerializationTest.java
@@ -0,0 +1,65 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.task;
+
+import static org.mockito.Mockito.mock;
+
+import java.time.Instant;
+
+import org.apache.james.JsonSerializationVerifier;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService.TargetFlag;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistencyTask.Details;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class SolveMailboxFlagInconsistencyTaskSerializationTest {
+
+    private static final SolveMailboxFlagInconsistenciesService SERVICE = 
mock(SolveMailboxFlagInconsistenciesService.class);
+
+    private static final Instant INSTANT = 
Instant.parse("2007-12-03T10:15:30.00Z");
+
+    @Test
+    void taskShouldBeSerializable() throws Exception {
+        
JsonSerializationVerifier.dtoModule(SolveMailboxFlagInconsistenciesTaskDTO.module(SERVICE))
+            .bean(new SolveMailboxFlagInconsistencyTask(SERVICE, 
TargetFlag.RECENT))
+            .json("{" +
+                "  \"type\":\"solve-mailbox-flag-inconsistencies\"," +
+                "  \"flagName\":\"RECENT\"" +
+                "}")
+            .verify();
+    }
+
+    @Test
+    void additionalInformationShouldBeSerializable() throws Exception {
+        
JsonSerializationVerifier.dtoModule(SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO.module())
+            .bean(new Details(INSTANT, 2,
+                ImmutableList.of("d2bee791-7e63-11ea-883c-95b84008f979", 
"ffffffff-7e63-11ea-883c-95b84008f979"),
+                TargetFlag.DELETED.name()))
+            .json("{" +
+                "    \"errors\": [\"d2bee791-7e63-11ea-883c-95b84008f979\", 
\"ffffffff-7e63-11ea-883c-95b84008f979\"]," +
+                "    \"processedMailboxEntries\": 2," +
+                "    \"timestamp\": \"2007-12-03T10:15:30Z\"," +
+                "    \"targetFlag\": \"DELETED\"," +
+                "    \"type\": \"solve-mailbox-flag-inconsistencies\"" +
+                "}")
+            .verify();
+    }
+}
diff --git 
a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/CassandraConsistencyTaskSerializationModule.java
 
b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/CassandraConsistencyTaskSerializationModule.java
index 735b4ace9f..d65aba895b 100644
--- 
a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/CassandraConsistencyTaskSerializationModule.java
+++ 
b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/CassandraConsistencyTaskSerializationModule.java
@@ -27,6 +27,9 @@ import 
org.apache.james.mailbox.cassandra.mail.task.MailboxMergingTaskRunner;
 import 
org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersService;
 import 
org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersTaskAdditionalInformationDTO;
 import 
org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersTaskDTO;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesTaskDTO;
 import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxInconsistenciesService;
 import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxInconsistenciesTaskAdditionalInformationDTO;
 import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxInconsistenciesTaskDTO;
@@ -146,4 +149,21 @@ public class CassandraConsistencyTaskSerializationModule 
extends AbstractModule
     public AdditionalInformationDTOModule<? extends 
TaskExecutionDetails.AdditionalInformation, ? extends  
AdditionalInformationDTO> 
webAdminSolveMessageInconsistenciesAdditionalInformation() {
         return 
SolveMessageInconsistenciesTaskAdditionalInformationDTO.module();
     }
+
+    @ProvidesIntoSet
+    public AdditionalInformationDTOModule<? extends 
TaskExecutionDetails.AdditionalInformation, ? extends AdditionalInformationDTO> 
solveMailboxFlagInconsistenciesAdditionalInformation() {
+        return 
SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO.module();
+    }
+
+    @Named(DTOModuleInjections.WEBADMIN_DTO)
+    @ProvidesIntoSet
+    public AdditionalInformationDTOModule<? extends 
TaskExecutionDetails.AdditionalInformation, ? extends AdditionalInformationDTO> 
webAdminSolveMailboxFlagInconsistenciesAdditionalInformation() {
+        return 
SolveMailboxFlagInconsistenciesTaskAdditionalInformationDTO.module();
+    }
+
+    @ProvidesIntoSet
+    public TaskDTOModule<? extends Task, ? extends TaskDTO> 
solveMailboxFlagInconsistenciesTask(SolveMailboxFlagInconsistenciesService 
solveMailboxFlagInconsistenciesService) {
+        return 
SolveMailboxFlagInconsistenciesTaskDTO.module(solveMailboxFlagInconsistenciesService);
+    }
+
 }
diff --git 
a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/webadmin/InconsistencySolvingRoutesModule.java
 
b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/webadmin/InconsistencySolvingRoutesModule.java
index f5197e15fb..1fa5b5db8d 100644
--- 
a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/webadmin/InconsistencySolvingRoutesModule.java
+++ 
b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/webadmin/InconsistencySolvingRoutesModule.java
@@ -19,7 +19,10 @@
 
 package org.apache.james.modules.webadmin;
 
+import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxRecentsDAO;
 import 
org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersService;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService;
 import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxInconsistenciesService;
 import 
org.apache.james.mailbox.cassandra.mail.task.SolveMessageInconsistenciesService;
 import org.apache.james.webadmin.Routes;
@@ -28,12 +31,16 @@ import org.apache.james.webadmin.routes.MailboxesRoutes;
 import org.apache.james.webadmin.routes.MessagesRoutes;
 import org.apache.james.webadmin.routes.RecomputeMailboxCountersRequestToTask;
 import 
org.apache.james.webadmin.routes.SolveMailboxInconsistenciesRequestToTask;
+import 
org.apache.james.webadmin.routes.SolveMessageDeletedInconsistenciesRequestToTask;
 import 
org.apache.james.webadmin.routes.SolveMessageInconsistenciesRequestToTask;
+import 
org.apache.james.webadmin.routes.SolveMessageRecentInconsistenciesRequestToTask;
 import org.apache.james.webadmin.service.CassandraMappingsService;
 import org.apache.james.webadmin.tasks.TaskFromRequestRegistry;
 
 import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
 import com.google.inject.Scopes;
+import com.google.inject.Singleton;
 import com.google.inject.multibindings.Multibinder;
 import com.google.inject.name.Names;
 
@@ -60,6 +67,8 @@ public class InconsistencySolvingRoutesModule extends 
AbstractModule {
 
             
multiBinder.addBinding().to(SolveMailboxInconsistenciesRequestToTask.class);
             
multiBinder.addBinding().to(RecomputeMailboxCountersRequestToTask.class);
+            
multiBinder.addBinding().to(SolveMessageDeletedInconsistenciesRequestToTask.class);
+            
multiBinder.addBinding().to(SolveMessageRecentInconsistenciesRequestToTask.class);
         }
     }
 
@@ -75,10 +84,34 @@ public class InconsistencySolvingRoutesModule extends 
AbstractModule {
         }
     }
 
+    public static class MailboxFlagInconsistencyModule extends AbstractModule {
+
+        @Override
+        public void configure() {
+            
Multibinder<SolveMailboxFlagInconsistenciesService.SolveMessageFlagInconsistencyStrategy>
 solveMailboxFlagInconsistenciesServiceMultibinder = 
Multibinder.newSetBinder(binder(), 
SolveMailboxFlagInconsistenciesService.SolveMessageFlagInconsistencyStrategy.class);
+            
solveMailboxFlagInconsistenciesServiceMultibinder.addBinding().to(SolveMailboxFlagInconsistenciesService.SolveMailboxDeletedFlagInconsistenciesStrategy.class);
+            
solveMailboxFlagInconsistenciesServiceMultibinder.addBinding().to(SolveMailboxFlagInconsistenciesService.SoleMailboxRecentFlagInconsistenciesStrategy.class);
+        }
+
+        @Provides
+        @Singleton
+        public 
SolveMailboxFlagInconsistenciesService.SolveMailboxDeletedFlagInconsistenciesStrategy
 
provideSolveMailboxDeletedFlagInconsistenciesStrategy(CassandraDeletedMessageDAO
 dao) {
+            return new 
SolveMailboxFlagInconsistenciesService.SolveMailboxDeletedFlagInconsistenciesStrategy(dao);
+        }
+
+
+        @Provides
+        @Singleton
+        public 
SolveMailboxFlagInconsistenciesService.SoleMailboxRecentFlagInconsistenciesStrategy
 provideSoleMailboxRecentFlagInconsistenciesStrategy(CassandraMailboxRecentsDAO 
dao) {
+            return new 
SolveMailboxFlagInconsistenciesService.SoleMailboxRecentFlagInconsistenciesStrategy(dao);
+        }
+    }
+
     @Override
     protected void configure() {
         install(new SolveRRTInconsistenciesModules());
         install(new SolveMailboxInconsistenciesModules());
         install(new SolveMessageInconsistenciesModules());
+        install(new MailboxFlagInconsistencyModule());
     }
 }
diff --git 
a/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/ConsistencyTasksIntegrationTest.java
 
b/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/ConsistencyTasksIntegrationTest.java
index 585cd0ce69..c0eef95628 100644
--- 
a/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/ConsistencyTasksIntegrationTest.java
+++ 
b/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/ConsistencyTasksIntegrationTest.java
@@ -34,6 +34,7 @@ import static org.apache.james.webadmin.Constants.SEPARATOR;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
 
 import java.io.IOException;
@@ -544,4 +545,83 @@ class ConsistencyTasksIntegrationTest {
 
         assertThat(testIMAPClient.readFirstMessage()).contains(MESSAGE);
     }
+
+    @Test
+    void shouldExposeSolveMessagesDeletedInconsistency(GuiceJamesServer 
server) throws Exception {
+        String solveInconsistenciesTaskId = with()
+            .queryParam("task", "SolveMessageDeletedInconsistencies")
+            .post("/mailboxes")
+            .jsonPath()
+            .get("taskId");
+
+        with()
+            .basePath(TasksRoutes.BASE)
+            .get(solveInconsistenciesTaskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("type", is("solve-mailbox-flag-inconsistencies"))
+            .body("additionalInformation.processedMailboxEntries", is(0))
+            .body("additionalInformation.targetFlag", is("DELETED"))
+            .body("additionalInformation.errors", hasSize(0));
+    }
+
+    @Test
+    void shouldSolveMessagesDeletedInconsistency(GuiceJamesServer server) 
throws Exception {
+        // Given a message and a messageDeleted inconsistency
+        smtpMessageSender.connect(LOCALHOST_IP, 
server.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .sendMessageWithHeaders(ALICE.asString(), BOB.asString(), MESSAGE);
+
+        Thread.sleep(1000);
+        TestingSession testingSession = 
server.getProbe(TestingSessionProbe.class).getTestingSession();
+
+        testIMAPClient.connect(JAMES_SERVER_HOST, 
server.getProbe(ImapGuiceProbe.class).getImapPort())
+            .login(BOB, BOB_PASSWORD)
+            .select(MailboxConstants.INBOX)
+            .awaitMessage(Awaitility.await());
+
+        testIMAPClient.setFlagsForAllMessagesInMailbox("\\Deleted");
+
+        // Make sure messageDeleted inconsistency is present
+        testingSession.execute("TRUNCATE messagedeleted");
+
+        // When we run solveInconsistenciesTask
+        String solveInconsistenciesTaskId = with()
+            .queryParam("task", "SolveMessageDeletedInconsistencies")
+            .post("/mailboxes")
+            .jsonPath()
+            .get("taskId");
+
+        // Then task details should be as expected
+        with()
+            .basePath(TasksRoutes.BASE)
+            .get(solveInconsistenciesTaskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("type", is("solve-mailbox-flag-inconsistencies"))
+            .body("additionalInformation.targetFlag", is("DELETED"))
+            .body("additionalInformation.processedMailboxEntries", is(1));
+
+        // And messageDeleted inconsistency should be solved
+        assertThat(testingSession.execute("SELECT * FROM 
messageDeleted").getAvailableWithoutFetching())
+            .isEqualTo(1);
+    }
+
+    @Test
+    void shouldExposeSolveMessagesRecentInconsistency(GuiceJamesServer server) 
throws Exception {
+        String solveInconsistenciesTaskId = with()
+            .queryParam("task", "SolveMessageRecentInconsistencies")
+            .post("/mailboxes")
+            .jsonPath()
+            .get("taskId");
+
+        with()
+            .basePath(TasksRoutes.BASE)
+            .get(solveInconsistenciesTaskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("type", is("solve-mailbox-flag-inconsistencies"))
+            .body("additionalInformation.targetFlag", is("RECENT"))
+            .body("additionalInformation.processedMailboxEntries", is(0))
+            .body("additionalInformation.errors", hasSize(0));
+    }
 }
diff --git 
a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/SolveMessageDeletedInconsistenciesRequestToTask.java
 
b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/SolveMessageDeletedInconsistenciesRequestToTask.java
new file mode 100644
index 0000000000..044649ec4d
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/SolveMessageDeletedInconsistenciesRequestToTask.java
@@ -0,0 +1,42 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.webadmin.routes;
+
+
+import jakarta.inject.Inject;
+
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService.TargetFlag;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistencyTask;
+import org.apache.james.webadmin.tasks.TaskFromRequestRegistry;
+import org.apache.james.webadmin.tasks.TaskRegistrationKey;
+
+public class SolveMessageDeletedInconsistenciesRequestToTask extends 
TaskFromRequestRegistry.TaskRegistration {
+    private static final TaskRegistrationKey REGISTRATION_KEY = 
TaskRegistrationKey.of("SolveMessageDeletedInconsistencies");
+
+    @Inject
+    public 
SolveMessageDeletedInconsistenciesRequestToTask(SolveMailboxFlagInconsistenciesService
 service) {
+        super(REGISTRATION_KEY, request -> toTask(service));
+    }
+
+    private static SolveMailboxFlagInconsistencyTask 
toTask(SolveMailboxFlagInconsistenciesService service) {
+        return new SolveMailboxFlagInconsistencyTask(service, 
TargetFlag.DELETED);
+    }
+}
diff --git 
a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/SolveMessageRecentInconsistenciesRequestToTask.java
 
b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/SolveMessageRecentInconsistenciesRequestToTask.java
new file mode 100644
index 0000000000..ffc2780c0a
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/SolveMessageRecentInconsistenciesRequestToTask.java
@@ -0,0 +1,42 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.webadmin.routes;
+
+
+import jakarta.inject.Inject;
+
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistenciesService.TargetFlag;
+import 
org.apache.james.mailbox.cassandra.mail.task.SolveMailboxFlagInconsistencyTask;
+import org.apache.james.webadmin.tasks.TaskFromRequestRegistry;
+import org.apache.james.webadmin.tasks.TaskRegistrationKey;
+
+public class SolveMessageRecentInconsistenciesRequestToTask extends 
TaskFromRequestRegistry.TaskRegistration {
+    private static final TaskRegistrationKey REGISTRATION_KEY = 
TaskRegistrationKey.of("SolveMessageRecentInconsistencies");
+
+    @Inject
+    public 
SolveMessageRecentInconsistenciesRequestToTask(SolveMailboxFlagInconsistenciesService
 service) {
+        super(REGISTRATION_KEY, request -> toTask(service));
+    }
+
+    private static SolveMailboxFlagInconsistencyTask 
toTask(SolveMailboxFlagInconsistenciesService service) {
+        return new SolveMailboxFlagInconsistencyTask(service, 
TargetFlag.RECENT);
+    }
+}


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

Reply via email to