You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/06/14 02:04:39 UTC
[james-project] 02/02: JAMES-3597 Exclude deleted messages from
JMAP Email/query
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit bd6277c44bdbe905c7b28dabe37a5a57959e572a
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Jun 11 13:46:55 2021 +0700
JAMES-3597 Exclude deleted messages from JMAP Email/query
---
.../mailbox/model/MultimailboxesSearchQuery.java | 12 +++++
.../integration/GetMessageListMethodTest.java | 48 --------------------
.../jmap/draft/methods/GetMessageListMethod.java | 4 +-
.../jmap/event/PopulateEmailQueryViewListener.java | 51 +++++++++++++++++++---
.../event/PopulateEmailQueryViewListenerTest.java | 46 +++++++++++++++++++
.../contract/EmailQueryMethodContract.scala | 5 +--
.../james/jmap/method/EmailQueryMethod.scala | 8 +++-
.../data/jmap/EmailQueryViewPopulator.java | 4 +-
.../PopulateEmailQueryViewRequestToTaskTest.java | 25 +++++++++++
9 files changed, 143 insertions(+), 60 deletions(-)
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MultimailboxesSearchQuery.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MultimailboxesSearchQuery.java
index 4785111..7db38f8 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MultimailboxesSearchQuery.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MultimailboxesSearchQuery.java
@@ -171,4 +171,16 @@ public class MultimailboxesSearchQuery {
public Namespace getNamespace() {
return namespace;
}
+
+ public MultimailboxesSearchQuery addCriterion(SearchQuery.Criterion criterion) {
+ return new MultimailboxesSearchQuery(
+ SearchQuery.builder()
+ .andCriteria(searchQuery.getCriteria())
+ .andCriteria(criterion)
+ .sorts(searchQuery.getSorts())
+ .build(),
+ inMailboxes,
+ notInMailboxes,
+ namespace);
+ }
}
diff --git a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/GetMessageListMethodTest.java b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/GetMessageListMethodTest.java
index 44ca726..bcdb080 100644
--- a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/GetMessageListMethodTest.java
+++ b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/GetMessageListMethodTest.java
@@ -94,7 +94,6 @@ import org.apache.james.utils.TestIMAPClient;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -222,7 +221,6 @@ public abstract class GetMessageListMethodTest {
.body(ARGUMENTS + ".messageIds", contains(messageId));
}
- @Ignore("JAMES-3597 Deleted messages are exposed over JMAP")
@Test
public void getMessageListShouldFilterMessagesMarkedAsDeleted() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, ALICE.asString(), "mailbox");
@@ -2187,29 +2185,6 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListHasKeywordShouldIgnoreDeleted() throws Exception {
- mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, ALICE.asString(), "mailbox");
-
- ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(ALICE.asString(), ALICE_MAILBOX,
- new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
- ComposedMessageId messageFlagged = mailboxProbe.appendMessage(ALICE.asString(), ALICE_MAILBOX,
- new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.DELETED));
-
- await();
-
- given()
- .header("Authorization", aliceAccessToken.asString())
- .body("[[\"getMessageList\", {\"filter\":{\"hasKeyword\":\"$Deleted\"}}, \"#0\"]]")
- .when()
- .post("/jmap")
- .then()
- .statusCode(200)
- .body(NAME, equalTo("messageList"))
- .body(ARGUMENTS + ".messageIds",
- containsInAnyOrder(messageFlagged.getMessageId().serialize(), messageNotFlagged.getMessageId().serialize()));
- }
-
- @Test
public void getMessageListHasKeywordShouldIgnoreRecent() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, ALICE.asString(), "mailbox");
@@ -2233,29 +2208,6 @@ public abstract class GetMessageListMethodTest {
}
@Test
- public void getMessageListNotKeywordShouldIgnoreDeleted() throws Exception {
- mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, ALICE.asString(), "mailbox");
-
- ComposedMessageId messageNotFlagged = mailboxProbe.appendMessage(ALICE.asString(), ALICE_MAILBOX,
- new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags());
- ComposedMessageId messageFlagged = mailboxProbe.appendMessage(ALICE.asString(), ALICE_MAILBOX,
- new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags(Flags.Flag.DELETED));
-
- await();
-
- given()
- .header("Authorization", aliceAccessToken.asString())
- .body("[[\"getMessageList\", {\"filter\":{\"notKeyword\":\"$Deleted\"}}, \"#0\"]]")
- .when()
- .post("/jmap")
- .then()
- .statusCode(200)
- .body(NAME, equalTo("messageList"))
- .body(ARGUMENTS + ".messageIds",
- containsInAnyOrder(messageFlagged.getMessageId().serialize(), messageNotFlagged.getMessageId().serialize()));
- }
-
- @Test
public void getMessageListNotKeywordShouldIgnoreRecent() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, ALICE.asString(), "mailbox");
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java
index bbf09d4..e655108 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java
@@ -19,6 +19,7 @@
package org.apache.james.jmap.draft.methods;
+import static javax.mail.Flags.Flag.DELETED;
import static org.apache.james.util.ReactorUtils.context;
import java.time.ZonedDateTime;
@@ -221,7 +222,8 @@ public class GetMessageListMethod implements Method {
.subscribeOn(Schedulers.parallel());
return searchQuery
- .flatMapMany(Throwing.function(query -> mailboxManager.search(query, mailboxSession, limit)))
+ .flatMapMany(Throwing.function(query ->
+ mailboxManager.search(query.addCriterion(SearchQuery.flagIsUnSet(DELETED)), mailboxSession, limit)))
.skip(position)
.reduce(GetMessageListResponse.builder(), GetMessageListResponse.Builder::messageId)
.map(GetMessageListResponse.Builder::build);
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/event/PopulateEmailQueryViewListener.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/event/PopulateEmailQueryViewListener.java
index 8dbf751..722cd52 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/event/PopulateEmailQueryViewListener.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/event/PopulateEmailQueryViewListener.java
@@ -19,6 +19,9 @@
package org.apache.james.jmap.event;
+import static javax.mail.Flags.Flag.DELETED;
+import static org.apache.james.util.ReactorUtils.publishIfPresent;
+
import java.io.IOException;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
@@ -35,17 +38,19 @@ import org.apache.james.mailbox.MessageIdManager;
import org.apache.james.mailbox.SessionProvider;
import org.apache.james.mailbox.events.MailboxEvents.Added;
import org.apache.james.mailbox.events.MailboxEvents.Expunged;
+import org.apache.james.mailbox.events.MailboxEvents.FlagsUpdated;
import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.FetchGroup;
+import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MessageId;
import org.apache.james.mailbox.model.MessageMetaData;
import org.apache.james.mailbox.model.MessageResult;
+import org.apache.james.mailbox.model.UpdatedFlags;
import org.apache.james.mime4j.dom.Message;
import org.apache.james.mime4j.stream.MimeConfig;
import org.reactivestreams.Publisher;
-import com.github.fge.lambdas.Throwing;
import com.google.common.collect.ImmutableList;
import reactor.core.publisher.Flux;
@@ -78,6 +83,7 @@ public class PopulateEmailQueryViewListener implements ReactiveGroupEventListene
@Override
public boolean isHandling(Event event) {
return event instanceof Added
+ || event instanceof FlagsUpdated
|| event instanceof Expunged
|| event instanceof MailboxDeletion;
}
@@ -90,6 +96,9 @@ public class PopulateEmailQueryViewListener implements ReactiveGroupEventListene
if (event instanceof Expunged) {
return handleExpunged((Expunged) event);
}
+ if (event instanceof FlagsUpdated) {
+ return handleFlagsUpdated((FlagsUpdated) event);
+ }
if (event instanceof MailboxDeletion) {
return handleMailboxDeletion((MailboxDeletion) event);
}
@@ -107,6 +116,31 @@ public class PopulateEmailQueryViewListener implements ReactiveGroupEventListene
.then();
}
+
+ private Publisher<Void> handleFlagsUpdated(FlagsUpdated flagsUpdated) {
+ MailboxSession session = sessionProvider.createSystemSession(flagsUpdated.getUsername());
+
+ Mono<Void> removeMessagesMarkedAsDeleted = Flux.fromIterable(flagsUpdated.getUpdatedFlags())
+ .filter(updatedFlags -> updatedFlags.isModifiedToSet(DELETED))
+ .map(UpdatedFlags::getMessageId)
+ .handle(publishIfPresent())
+ .concatMap(messageId -> view.delete(flagsUpdated.getMailboxId(), messageId))
+ .then();
+
+ Mono<Void> addMessagesNoLongerMarkedAsDeleted = Flux.fromIterable(flagsUpdated.getUpdatedFlags())
+ .filter(updatedFlags -> updatedFlags.isModifiedToUnset(DELETED))
+ .map(UpdatedFlags::getMessageId)
+ .handle(publishIfPresent())
+ .concatMap(messageId ->
+ Flux.from(messageIdManager.getMessagesReactive(ImmutableList.of(messageId), FetchGroup.HEADERS, session))
+ .next())
+ .concatMap(message -> handleAdded(flagsUpdated.getMailboxId(), message))
+ .then();
+
+ return removeMessagesMarkedAsDeleted
+ .then(addMessagesNoLongerMarkedAsDeleted);
+ }
+
private Mono<Void> handleAdded(Added added) {
MailboxSession session = sessionProvider.createSystemSession(added.getUsername());
return Flux.fromStream(added.getUids().stream()
@@ -117,14 +151,21 @@ public class PopulateEmailQueryViewListener implements ReactiveGroupEventListene
private Mono<Void> handleAdded(Added added, MessageMetaData messageMetaData, MailboxSession session) {
MessageId messageId = messageMetaData.getMessageId();
- ZonedDateTime receivedAt = ZonedDateTime.ofInstant(messageMetaData.getInternalDate().toInstant(), ZoneOffset.UTC);
return Flux.from(messageIdManager.getMessagesReactive(ImmutableList.of(messageId), FetchGroup.HEADERS, session))
.next()
- .map(Throwing.function(this::parseMessage))
- .map(message -> Optional.ofNullable(message.getDate()).orElse(messageMetaData.getInternalDate()))
+ .filter(message -> !message.getFlags().contains(DELETED))
+ .flatMap(messageResult -> handleAdded(added.getMailboxId(), messageResult));
+ }
+
+ public Mono<Void> handleAdded(MailboxId mailboxId, MessageResult messageResult) {
+ ZonedDateTime receivedAt = ZonedDateTime.ofInstant(messageResult.getInternalDate().toInstant(), ZoneOffset.UTC);
+
+ return Mono.fromCallable(() -> parseMessage(messageResult))
+ .map(message -> Optional.ofNullable(message.getDate()).orElse(messageResult.getInternalDate()))
.map(date -> ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC))
- .flatMap(sentAt -> view.save(added.getMailboxId(), sentAt, receivedAt, messageId));
+ .flatMap(sentAt -> view.save(mailboxId, sentAt, receivedAt, messageResult.getMessageId()))
+ .then();
}
private Message parseMessage(MessageResult messageResult) throws IOException, MailboxException {
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/event/PopulateEmailQueryViewListenerTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/event/PopulateEmailQueryViewListenerTest.java
index e77ace4..98a75c3 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/event/PopulateEmailQueryViewListenerTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/event/PopulateEmailQueryViewListenerTest.java
@@ -19,6 +19,7 @@
package org.apache.james.jmap.event;
+import static javax.mail.Flags.Flag.DELETED;
import static org.assertj.core.api.Assertions.assertThat;
import java.nio.charset.StandardCharsets;
@@ -26,6 +27,8 @@ import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Date;
+import javax.mail.Flags;
+
import org.apache.james.core.Username;
import org.apache.james.events.Group;
import org.apache.james.events.InVMEventBus;
@@ -41,6 +44,7 @@ import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
import org.apache.james.mailbox.model.ComposedMessageId;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageRange;
import org.apache.james.mailbox.store.FakeAuthenticator;
import org.apache.james.mailbox.store.FakeAuthorizator;
import org.apache.james.mailbox.store.SessionProviderImpl;
@@ -129,6 +133,48 @@ public class PopulateEmailQueryViewListenerTest {
}
@Test
+ void appendingADeletedMessageSHouldNotAddItToTheView() throws Exception {
+ inboxMessageManager.appendMessage(
+ MessageManager.AppendCommand.builder()
+ .withInternalDate(Date.from(ZonedDateTime.parse("2014-10-30T15:12:00Z").toInstant()))
+ .withFlags(new Flags(DELETED))
+ .build(emptyMessage(Date.from(ZonedDateTime.parse("2014-10-30T14:12:00Z").toInstant()))),
+ mailboxSession).getId();
+
+ assertThat(view.listMailboxContent(inboxId, Limit.limit(12)).collectList().block())
+ .isEmpty();
+ }
+
+ @Test
+ void removingDeletedFlagsShouldAddItToTheView() throws Exception {
+ ComposedMessageId composedId = inboxMessageManager.appendMessage(
+ MessageManager.AppendCommand.builder()
+ .withInternalDate(Date.from(ZonedDateTime.parse("2014-10-30T15:12:00Z").toInstant()))
+ .withFlags(new Flags(DELETED))
+ .build(emptyMessage(Date.from(ZonedDateTime.parse("2014-10-30T14:12:00Z").toInstant()))),
+ mailboxSession).getId();
+
+ inboxMessageManager.setFlags(new Flags(), MessageManager.FlagsUpdateMode.REPLACE, MessageRange.all(), mailboxSession);
+
+ assertThat(view.listMailboxContent(inboxId, Limit.limit(12)).collectList().block())
+ .containsOnly(composedId.getMessageId());
+ }
+
+ @Test
+ void addingDeletedFlagsShouldRemoveItToTheView() throws Exception {
+ inboxMessageManager.appendMessage(
+ MessageManager.AppendCommand.builder()
+ .withInternalDate(Date.from(ZonedDateTime.parse("2014-10-30T15:12:00Z").toInstant()))
+ .build(emptyMessage(Date.from(ZonedDateTime.parse("2014-10-30T14:12:00Z").toInstant()))),
+ mailboxSession).getId();
+
+ inboxMessageManager.setFlags(new Flags(DELETED), MessageManager.FlagsUpdateMode.REPLACE, MessageRange.all(), mailboxSession);
+
+ assertThat(view.listMailboxContent(inboxId, Limit.limit(12)).collectList().block())
+ .isEmpty();
+ }
+
+ @Test
void deletingMailboxShouldClearTheView() throws Exception {
inboxMessageManager.appendMessage(
MessageManager.AppendCommand.builder()
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/EmailQueryMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
index f2b1cbd..ca93414 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
@@ -55,7 +55,7 @@ import org.apache.james.util.ClassLoaderUtils
import org.apache.james.utils.DataProbeImpl
import org.awaitility.Awaitility
import org.awaitility.Durations.ONE_HUNDRED_MILLISECONDS
-import org.junit.jupiter.api.{BeforeEach, Disabled, Test}
+import org.junit.jupiter.api.{BeforeEach, Test}
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.{Arguments, MethodSource, ValueSource}
import org.threeten.extra.Seconds
@@ -206,9 +206,8 @@ trait EmailQueryMethodContract {
}
}
- @Disabled("JAMES-3597 Deleted messages are exposed over JMAP")
@Test
- def messagesMarkedAsDeeltedShouldNotBeExposedOverJMAP(server: GuiceJamesServer): Unit = {
+ def messagesMarkedAsDeletedShouldNotBeExposedOverJMAP(server: GuiceJamesServer): Unit = {
val mailboxProbe = server.getProbe(classOf[MailboxProbeImpl])
mailboxProbe.createMailbox(MailboxPath.inbox(BOB))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
index 186e80c..ad4cace 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
@@ -23,6 +23,7 @@ import java.time.ZonedDateTime
import cats.implicits._
import eu.timepit.refined.auto._
import javax.inject.Inject
+import javax.mail.Flags.Flag.DELETED
import org.apache.james.jmap.JMAPConfiguration
import org.apache.james.jmap.api.projections.EmailQueryView
import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, JMAP_CORE, JMAP_MAIL}
@@ -36,7 +37,7 @@ import org.apache.james.jmap.routes.SessionSupplier
import org.apache.james.jmap.utils.search.MailboxFilter
import org.apache.james.jmap.utils.search.MailboxFilter.QueryFilter
import org.apache.james.mailbox.exception.MailboxNotFoundException
-import org.apache.james.mailbox.model.{MailboxId, MessageId, MultimailboxesSearchQuery}
+import org.apache.james.mailbox.model.{MailboxId, MessageId, MultimailboxesSearchQuery, SearchQuery}
import org.apache.james.mailbox.{MailboxManager, MailboxSession}
import org.apache.james.metrics.api.MetricFactory
import org.apache.james.util.streams.{Limit => JavaLimit}
@@ -151,7 +152,10 @@ class EmailQueryMethod @Inject() (serializer: EmailQuerySerializer,
limit = Some(limitToUse).filterNot(used => request.limit.map(_.value).contains(used.value)))
private def executeQueryAgainstSearchIndex(mailboxSession: MailboxSession, searchQuery: MultimailboxesSearchQuery, position: Position, limitToUse: Limit): SMono[Seq[MessageId]] =
- SFlux.fromPublisher(mailboxManager.search(searchQuery, mailboxSession, position.value + limitToUse))
+ SFlux.fromPublisher(mailboxManager.search(
+ searchQuery.addCriterion(SearchQuery.flagIsUnSet(DELETED)),
+ mailboxSession,
+ position.value + limitToUse))
.drop(position.value)
.collectSeq()
diff --git a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
index 7a77db5..76c1e0e 100644
--- a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
+++ b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
@@ -19,6 +19,7 @@
package org.apache.james.webadmin.data.jmap;
+import static javax.mail.Flags.Flag.DELETED;
import static org.apache.james.mailbox.MailboxManager.MailboxSearchFetchType.Minimal;
import java.io.IOException;
@@ -134,7 +135,8 @@ public class EmailQueryViewPopulator {
return Iterators.toFlux(usersRepository.list())
.map(mailboxManager::createSystemSession)
.doOnNext(any -> progress.incrementProcessedUserCount())
- .flatMap(session -> listUserMailboxMessages(progress, session), USER_CONCURRENCY);
+ .flatMap(session -> listUserMailboxMessages(progress, session), USER_CONCURRENCY)
+ .filter(messageResult -> !messageResult.getFlags().contains(DELETED));
} catch (UsersRepositoryException e) {
return Flux.error(e);
}
diff --git a/server/protocols/webadmin/webadmin-jmap/src/test/java/org/apache/james/webadmin/data/jmap/PopulateEmailQueryViewRequestToTaskTest.java b/server/protocols/webadmin/webadmin-jmap/src/test/java/org/apache/james/webadmin/data/jmap/PopulateEmailQueryViewRequestToTaskTest.java
index 402ed7e..4cda472 100644
--- a/server/protocols/webadmin/webadmin-jmap/src/test/java/org/apache/james/webadmin/data/jmap/PopulateEmailQueryViewRequestToTaskTest.java
+++ b/server/protocols/webadmin/webadmin-jmap/src/test/java/org/apache/james/webadmin/data/jmap/PopulateEmailQueryViewRequestToTaskTest.java
@@ -22,10 +22,13 @@ package org.apache.james.webadmin.data.jmap;
import static io.restassured.RestAssured.given;
import static io.restassured.RestAssured.when;
import static io.restassured.RestAssured.with;
+import static javax.mail.Flags.Flag.DELETED;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
+import javax.mail.Flags;
+
import org.apache.james.core.Username;
import org.apache.james.domainlist.api.DomainList;
import org.apache.james.jmap.memory.projections.MemoryEmailQueryView;
@@ -268,6 +271,28 @@ class PopulateEmailQueryViewRequestToTaskTest {
}
@Test
+ void populateShouldNotUpdateProjectionForDeletedMessages() throws Exception {
+ ComposedMessageId messageId = mailboxManager.getMailbox(bobInboxboxId, bobSession).appendMessage(
+ MessageManager.AppendCommand.builder()
+ .withFlags(new Flags(DELETED))
+ .build("header: value\r\n\r\nbody"),
+ bobSession).getId();
+
+ String taskId = with()
+ .queryParam("action", "populateEmailQueryView")
+ .post()
+ .jsonPath()
+ .get("taskId");
+
+ with()
+ .basePath(TasksRoutes.BASE)
+ .get(taskId + "/await");
+
+ assertThat(view.listMailboxContent(messageId.getMailboxId(), Limit.from(12)).collectList().block())
+ .isEmpty();
+ }
+
+ @Test
void populateShouldBeIdempotent() throws Exception {
ComposedMessageId messageId = mailboxManager.getMailbox(bobInboxboxId, bobSession).appendMessage(
MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"),
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org