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 6d3033b36288a502243e7f256f6a708d4c615085 Author: Tung Tran <vtt...@linagora.com> AuthorDate: Wed May 24 11:21:13 2023 +0700 DeletedMessagesVault API - support limit query --- .../vault/blob/BlobStoreDeletedMessageVault.java | 5 ++- .../org/apache/james/vault/dto/query/QueryDTO.java | 23 +++++++++-- .../james/vault/dto/query/QueryTranslator.java | 4 +- .../java/org/apache/james/vault/search/Query.java | 23 +++++++++++ .../james/vault/DeletedMessageVaultContract.java | 16 ++++++++ .../dto/query/QueryElementSerializerTest.java | 7 +++- .../james/vault/dto/query/QueryTranslatorTest.java | 19 +++++++++- .../docs/modules/ROOT/pages/operate/webadmin.adoc | 10 +++++ .../vault/DeletedMessageVaultIntegrationTest.java | 26 +++++++++++++ .../routes/DeletedMessagesVaultRoutesTest.java | 44 ++++++++++++++++++++++ .../WebadminApiQuerySerializationContractTest.java | 23 +++++------ src/site/markdown/server/manage-webadmin.md | 9 +++++ 12 files changed, 188 insertions(+), 21 deletions(-) diff --git a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVault.java b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVault.java index c1b7a2ddd8..c3bfbf13c8 100644 --- a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVault.java +++ b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVault.java @@ -139,10 +139,13 @@ public class BlobStoreDeletedMessageVault implements DeletedMessageVault { } private Flux<DeletedMessage> searchOn(Username username, Query query) { - return Flux.from(messageMetadataVault.listRelatedBuckets()) + Flux<DeletedMessage> filterPublisher = Flux.from(messageMetadataVault.listRelatedBuckets()) .concatMap(bucketName -> messageMetadataVault.listMessages(bucketName, username)) .map(DeletedMessageWithStorageInformation::getDeletedMessage) .filter(query.toPredicate()); + return query.getLimit() + .map(filterPublisher::take) + .orElse(filterPublisher); } @Override diff --git a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/dto/query/QueryDTO.java b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/dto/query/QueryDTO.java index f72ff0ccae..7f56275ec6 100644 --- a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/dto/query/QueryDTO.java +++ b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/dto/query/QueryDTO.java @@ -21,6 +21,7 @@ package org.apache.james.vault.dto.query; import java.util.List; import java.util.Objects; +import java.util.Optional; import org.apache.james.vault.search.Combinator; @@ -35,16 +36,25 @@ public class QueryDTO implements QueryElement { @VisibleForTesting static QueryDTO and(QueryElement... queryElements) { - return new QueryDTO(Combinator.AND.getValue(), ImmutableList.copyOf(queryElements)); + return new QueryDTO(Combinator.AND.getValue(), ImmutableList.copyOf(queryElements), Optional.empty()); + } + + @VisibleForTesting + static QueryDTO and(Long limit, QueryElement... queryElements) { + return new QueryDTO(Combinator.AND.getValue(), ImmutableList.copyOf(queryElements), Optional.ofNullable(limit)); } private final String combinator; private final List<QueryElement> criteria; + private final Optional<Long> limit; @JsonCreator - public QueryDTO(@JsonProperty("combinator") String combinator, @JsonProperty("criteria") List<QueryElement> criteria) { + public QueryDTO(@JsonProperty("combinator") String combinator, + @JsonProperty("criteria") List<QueryElement> criteria, + @JsonProperty("limit") Optional<Long> limit) { this.combinator = combinator; this.criteria = criteria; + this.limit = Optional.ofNullable(limit).orElse(Optional.empty()); } public String getCombinator() { @@ -55,19 +65,24 @@ public class QueryDTO implements QueryElement { return criteria; } + public Optional<Long> getLimit() { + return limit; + } + @Override public final boolean equals(Object o) { if (o instanceof QueryDTO) { QueryDTO queryDTO = (QueryDTO) o; return Objects.equals(this.combinator, queryDTO.getCombinator()) - && Objects.equals(this.criteria, queryDTO.getCriteria()); + && Objects.equals(this.criteria, queryDTO.getCriteria()) + && Objects.equals(this.limit, queryDTO.getLimit()); } return false; } @Override public final int hashCode() { - return Objects.hash(combinator, criteria); + return Objects.hash(combinator, criteria, limit); } } diff --git a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/dto/query/QueryTranslator.java b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/dto/query/QueryTranslator.java index 6619c8c845..2ed94abc74 100644 --- a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/dto/query/QueryTranslator.java +++ b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/dto/query/QueryTranslator.java @@ -198,7 +198,7 @@ public class QueryTranslator { List<QueryElement> queryElements = query.getCriteria().stream() .map(this::toDTO) .collect(ImmutableList.toImmutableList()); - return new QueryDTO(Combinator.AND.getValue(), queryElements); + return new QueryDTO(Combinator.AND.getValue(), queryElements, query.getLimit()); } private CriterionDTO toDTO(Criterion<?> criterion) { @@ -224,7 +224,7 @@ public class QueryTranslator { return Query.and(queryDTO.getCriteria().stream() .map(queryElement -> (CriterionDTO) queryElement) .map(Throwing.function(this::translate)) - .collect(ImmutableList.toImmutableList())); + .collect(ImmutableList.toImmutableList()), queryDTO.getLimit()); } private boolean combinatorIsValid(String combinator) { diff --git a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/search/Query.java b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/search/Query.java index f73e067ecd..779f3ac9f8 100644 --- a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/search/Query.java +++ b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/search/Query.java @@ -20,10 +20,12 @@ package org.apache.james.vault.search; import java.util.List; +import java.util.Optional; import java.util.function.Predicate; import org.apache.james.vault.DeletedMessage; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; public class Query { @@ -34,14 +36,31 @@ public class Query { return new Query(criteria); } + public static Query and(List<Criterion<?>> criteria, Optional<Long> limit) { + return new Query(criteria, limit.orElse(null)); + } + public static Query of(Criterion<?>... criteria) { return new Query(ImmutableList.copyOf(criteria)); } + public static Query of(long limit, List<Criterion<?>> criteria) { + return new Query(criteria, limit); + } + private final List<Criterion<?>> criteria; + private final Optional<Long> limit; + private Query(List<Criterion<?>> criteria) { this.criteria = criteria; + this.limit = Optional.empty(); + } + + public Query(List<Criterion<?>> criteria, Long limit) { + Preconditions.checkArgument(limit == null || limit > 0, "Limit should be strictly positive"); + this.criteria = criteria; + this.limit = Optional.ofNullable(limit); } public Predicate<DeletedMessage> toPredicate() { @@ -54,4 +73,8 @@ public class Query { public List<Criterion<?>> getCriteria() { return criteria; } + + public Optional<Long> getLimit() { + return limit; + } } diff --git a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultContract.java b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultContract.java index 7d3e9d953e..cf82d47a4a 100644 --- a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultContract.java +++ b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultContract.java @@ -37,6 +37,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.io.ByteArrayInputStream; import java.time.Clock; import java.time.Duration; +import java.util.List; import org.apache.james.mailbox.inmemory.InMemoryMessageId; import org.apache.james.task.Task; @@ -127,6 +128,21 @@ public interface DeletedMessageVaultContract { .containsOnly(DELETED_MESSAGE, DELETED_MESSAGE_2); } + @Test + default void searchAllShouldSupportLimitQuery() { + Mono.from(getVault().append(DELETED_MESSAGE, new ByteArrayInputStream(CONTENT))).block(); + Mono.from(getVault().append(DELETED_MESSAGE_2, new ByteArrayInputStream(CONTENT))).block(); + DeletedMessage deletedMessage3 = DELETED_MESSAGE_GENERATOR.apply(InMemoryMessageId.of(33).getRawId()); + Mono.from(getVault().append(deletedMessage3, new ByteArrayInputStream(CONTENT))).block(); + + assertThat(Flux.from(getVault().search(USERNAME, Query.of(1, List.of()))).collectList().block()) + .hasSize(1); + assertThat(Flux.from(getVault().search(USERNAME, Query.of(3, List.of()))).collectList().block()) + .containsExactlyInAnyOrder(DELETED_MESSAGE, DELETED_MESSAGE_2, deletedMessage3); + assertThat(Flux.from(getVault().search(USERNAME, Query.of(4, List.of()))).collectList().block()) + .containsExactlyInAnyOrder(DELETED_MESSAGE, DELETED_MESSAGE_2, deletedMessage3); + } + @Test default void searchShouldReturnMatchingItems() { Mono.from(getVault().append(DELETED_MESSAGE_2, new ByteArrayInputStream(CONTENT))).block(); diff --git a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/dto/query/QueryElementSerializerTest.java b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/dto/query/QueryElementSerializerTest.java index cc983fd7b1..77ba5f63e9 100644 --- a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/dto/query/QueryElementSerializerTest.java +++ b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/dto/query/QueryElementSerializerTest.java @@ -22,6 +22,7 @@ package org.apache.james.vault.dto.query; import static org.apache.james.vault.DeletedMessageFixture.SUBJECT; import static org.apache.mailet.base.MailAddressFixture.SENDER; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import org.apache.james.vault.search.FieldName; import org.apache.james.vault.search.Operator; import org.junit.jupiter.api.BeforeEach; @@ -38,6 +39,7 @@ class QueryElementSerializerTest { @BeforeEach void beforeEach() { ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new Jdk8Module()); queryElementSerializer = new QueryElementSerializer(objectMapper); } @@ -54,9 +56,11 @@ class QueryElementSerializerTest { JsonAssertions.assertThatJson(queryElementSerializer.serialize(queryDTO)) .isEqualTo("{ " + " \"combinator\": \"and\", " + + " \"limit\": null, " + " \"criteria\": [ " + " { " + " \"combinator\": \"and\", " + + " \"limit\": null, " + " \"criteria\": [ " + " {\"fieldName\": \"subject\", \"operator\": \"contains\", \"value\": \"" + SUBJECT + "\"}," + " {\"fieldName\": \"sender\", \"operator\": \"equals\", \"value\": \"" + SENDER.asString() + "\"}" + @@ -70,7 +74,7 @@ class QueryElementSerializerTest { @Test void shouldSerializeFlattenStructure() throws Exception { - QueryDTO queryDTO = QueryDTO.and( + QueryDTO queryDTO = QueryDTO.and(1L, CriterionDTO.from(FieldName.SUBJECT, Operator.CONTAINS, SUBJECT), CriterionDTO.from(FieldName.SENDER, Operator.EQUALS, SENDER.asString()), CriterionDTO.from(FieldName.HAS_ATTACHMENT, Operator.EQUALS, "true") @@ -79,6 +83,7 @@ class QueryElementSerializerTest { JsonAssertions.assertThatJson(queryElementSerializer.serialize(queryDTO)) .isEqualTo("{ " + " \"combinator\": \"and\", " + + " \"limit\": 1, " + " \"criteria\": [ " + " {\"fieldName\": \"subject\", \"operator\": \"contains\", \"value\": \"" + SUBJECT + "\"}," + " {\"fieldName\": \"sender\", \"operator\": \"equals\", \"value\": \"" + SENDER.asString() + "\"}," + diff --git a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/dto/query/QueryTranslatorTest.java b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/dto/query/QueryTranslatorTest.java index 301d720c28..6450b33a82 100644 --- a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/dto/query/QueryTranslatorTest.java +++ b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/dto/query/QueryTranslatorTest.java @@ -24,6 +24,8 @@ import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.time.ZonedDateTime; +import java.util.List; +import java.util.Optional; import org.apache.james.core.MailAddress; import org.apache.james.mailbox.inmemory.InMemoryId; @@ -48,7 +50,7 @@ class QueryTranslatorTest { @Test void translateShouldThrowWhenPassingNotAndOperator() { - assertThatThrownBy(() -> queryTranslator.translate(new QueryDTO("or", ImmutableList.of()))) + assertThatThrownBy(() -> queryTranslator.translate(new QueryDTO("or", ImmutableList.of(), Optional.empty()))) .isInstanceOf(IllegalArgumentException.class) .hasMessage("combinator 'or' is not yet handled"); } @@ -56,7 +58,7 @@ class QueryTranslatorTest { @Test void translateShouldNotThrowWhenPassingNullOperator() { String nullOperator = null; - assertThatCode(() -> queryTranslator.translate(new QueryDTO(nullOperator, ImmutableList.of()))) + assertThatCode(() -> queryTranslator.translate(new QueryDTO(nullOperator, ImmutableList.of(), Optional.empty()))) .doesNotThrowAnyException(); } @@ -216,4 +218,17 @@ class QueryTranslatorTest { new CriterionDTO(FieldName.HAS_ATTACHMENT.getValue(), Operator.EQUALS.getValue(), "true") )); } + + @Test + void toDTOShouldSuccessWhenHasLimitQuery() throws Exception { + Query query = Query.of(11, + List.of(CriterionFactory.subject().contains("james"), + CriterionFactory.hasSender(new MailAddress("u...@james.org")), + CriterionFactory.hasAttachment(true))); + + assertThat(queryTranslator.toDTO(query)).isEqualTo(QueryDTO.and(11L, + new CriterionDTO(FieldName.SUBJECT.getValue(), Operator.CONTAINS.getValue(), "james"), + new CriterionDTO(FieldName.SENDER.getValue(), Operator.EQUALS.getValue(), "u...@james.org"), + new CriterionDTO(FieldName.HAS_ATTACHMENT.getValue(), Operator.EQUALS.getValue(), "true"))); + } } \ No newline at end of file diff --git a/server/apps/distributed-app/docs/modules/ROOT/pages/operate/webadmin.adoc b/server/apps/distributed-app/docs/modules/ROOT/pages/operate/webadmin.adoc index fa1a311569..72a4d6bb0f 100644 --- a/server/apps/distributed-app/docs/modules/ROOT/pages/operate/webadmin.adoc +++ b/server/apps/distributed-app/docs/modules/ROOT/pages/operate/webadmin.adoc @@ -4610,6 +4610,16 @@ criterion list to represent `matching all deleted messages`: } .... +* For limiting the number of restored messages, you can use the `limit` query property: + +.... +{ + "combinator": "and", + "limit": 99 + "criteria": [] +} +.... + *Warning*: Current web-admin uses `US` locale as the default. Therefore, there might be some conflicts when using String `containsIgnoreCase` comparators to apply on the String data of other special locales stored diff --git a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/DeletedMessageVaultIntegrationTest.java b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/DeletedMessageVaultIntegrationTest.java index 466fb8e05b..89695a57d3 100644 --- a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/DeletedMessageVaultIntegrationTest.java +++ b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/vault/DeletedMessageVaultIntegrationTest.java @@ -350,6 +350,32 @@ public abstract class DeletedMessageVaultIntegrationTest { .isEqualTo(0); } + @Test + void postShouldRestoreMatchingMessagesWhenQueryLimit() { + bartSendMessageToHomerWithSubject("aaaa"); + bartSendMessageToHomerWithSubject("aaaa"); + WAIT_TWO_MINUTES.untilAsserted(() -> assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(2)); + + homerDeletesMessages(listMessageIdsForAccount(homerAccessToken)); + + WAIT_TWO_MINUTES.untilAsserted(() -> assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(0)); + + String query = "{" + + " \"combinator\": \"and\"," + + " \"limit\": 1," + + " \"criteria\": [" + + " {" + + " \"fieldName\": \"subject\"," + + " \"operator\": \"equals\"," + + " \"value\": \"aaaa\"" + + " }" + + " ]" + + "}"; + restoreMessagesForUserWithQuery(webAdminApi, HOMER, query); + + WAIT_TWO_MINUTES.untilAsserted(() -> assertThat(listMessageIdsForAccount(homerAccessToken)).hasSize(1)); + } + @Test void imapMovedMessageShouldNotEndUpInTheVault(GuiceJamesServer jmapServer) throws Exception { bartSendMessageToHomer(); diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java index 88032e17eb..39571fd587 100644 --- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java +++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java @@ -25,6 +25,7 @@ import static io.restassured.RestAssured.with; import static org.apache.james.vault.DeletedMessageFixture.CONTENT; import static org.apache.james.vault.DeletedMessageFixture.DELETED_MESSAGE; import static org.apache.james.vault.DeletedMessageFixture.DELETED_MESSAGE_2; +import static org.apache.james.vault.DeletedMessageFixture.DELETED_MESSAGE_GENERATOR; import static org.apache.james.vault.DeletedMessageFixture.DELETION_DATE; import static org.apache.james.vault.DeletedMessageFixture.DELIVERY_DATE; import static org.apache.james.vault.DeletedMessageFixture.FINAL_STAGE; @@ -1793,6 +1794,49 @@ class DeletedMessagesVaultRoutesTest { .isFalse(); } + @Test + void restoreShouldSupportLimitQuery() throws Exception { + Mono.from(vault.append(FINAL_STAGE.get() + .subject("subject contains should match") + .build(), new ByteArrayInputStream(CONTENT))).block(); + + DeletedMessage deletedMessage2 = DELETED_MESSAGE_GENERATOR.apply(InMemoryMessageId.of(22).getRawId()); + + Mono.from(vault.append(deletedMessage2, new ByteArrayInputStream(CONTENT))).block(); + + String query = "{" + + " \"combinator\": \"and\"," + + " \"limit\": 1," + + " \"criteria\": [" + + " {" + + " \"fieldName\": \"sender\"," + + " \"operator\": \"equals\"," + + " \"value\": \"" + SENDER.asString() + "\"" + + " }" + + " ]" + + "}"; + + String taskId = + given() + .queryParam("action", "restore") + .body(query) + .when() + .post(BOB_PATH) + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")) + .body("additionalInformation.successfulRestoreCount", is(1)); + + assertThat(restoreMessageContents(USERNAME)) + .hasSize(1); + } + } @Nested diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/WebadminApiQuerySerializationContractTest.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/WebadminApiQuerySerializationContractTest.java index 7446c165b7..aadc8d736d 100644 --- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/WebadminApiQuerySerializationContractTest.java +++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/WebadminApiQuerySerializationContractTest.java @@ -19,6 +19,7 @@ package org.apache.james.webadmin.vault.routes; import java.time.ZonedDateTime; +import java.util.Optional; import java.util.stream.Stream; import org.apache.james.mailbox.model.MailboxId; @@ -48,47 +49,47 @@ class WebadminApiQuerySerializationContractTest { private static final String HAS_ATTACHMENT_FILE = "has_attachment.json"; private static final QueryDTO HAS_ATTACHMENT_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.HAS_ATTACHMENT.getValue(), Operator.EQUALS.getValue(), "true"))); + ImmutableList.of(new CriterionDTO(FieldName.HAS_ATTACHMENT.getValue(), Operator.EQUALS.getValue(), "true")), Optional.empty()); private static final String HAS_NO_ATTACHMENT_FILE = "has_no_attachment.json"; private static final QueryDTO HAS_NO_ATTACHMENT_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.HAS_ATTACHMENT.getValue(), Operator.EQUALS.getValue(), "false"))); + ImmutableList.of(new CriterionDTO(FieldName.HAS_ATTACHMENT.getValue(), Operator.EQUALS.getValue(), "false")), Optional.empty()); private static final String HAS_SENDER_FILE = "has_sender.json"; private static final QueryDTO HAS_SENDER_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.SENDER.getValue(), Operator.EQUALS.getValue(), USER_JAMES))); + ImmutableList.of(new CriterionDTO(FieldName.SENDER.getValue(), Operator.EQUALS.getValue(), USER_JAMES)), Optional.empty()); private static final String CONTAINS_RECIPIENT_FILE = "contains_recipient.json"; private static final QueryDTO CONTAINS_RECIPIENT_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.RECIPIENTS.getValue(), Operator.CONTAINS.getValue(), USER_JAMES))); + ImmutableList.of(new CriterionDTO(FieldName.RECIPIENTS.getValue(), Operator.CONTAINS.getValue(), USER_JAMES)), Optional.empty()); private static final String CONTAINS_ORIGIN_MAILBOX_FILE = "contains_origin_mailbox.json"; private static final QueryDTO CONTAINS_ORIGIN_MAILBOX_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.ORIGIN_MAILBOXES.getValue(), Operator.CONTAINS.getValue(), MAILBOX_1_ID.serialize()))); + ImmutableList.of(new CriterionDTO(FieldName.ORIGIN_MAILBOXES.getValue(), Operator.CONTAINS.getValue(), MAILBOX_1_ID.serialize())), Optional.empty()); private static final String DELIVERY_BEFORE_FILE = "zoned_date_time_before_or_equals.json"; private static final QueryDTO DELIVERY_BEFORE_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.DELIVERY_DATE.getValue(), Operator.BEFORE_OR_EQUALS.getValue(), ZONED_DATE_TIME.toString()))); + ImmutableList.of(new CriterionDTO(FieldName.DELIVERY_DATE.getValue(), Operator.BEFORE_OR_EQUALS.getValue(), ZONED_DATE_TIME.toString())), Optional.empty()); private static final String DELETED_AFTER_FILE = "zoned_date_time_after_or_equals.json"; private static final QueryDTO DELETED_AFTER_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.DELETION_DATE.getValue(), Operator.AFTER_OR_EQUALS.getValue(), ZONED_DATE_TIME.toString()))); + ImmutableList.of(new CriterionDTO(FieldName.DELETION_DATE.getValue(), Operator.AFTER_OR_EQUALS.getValue(), ZONED_DATE_TIME.toString())), Optional.empty()); private static final String SUBJECT_CONTAINS_FILE = "string_contains.json"; private static final QueryDTO SUBJECT_CONTAINS_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.SUBJECT.getValue(), Operator.CONTAINS.getValue(), SUBJECT))); + ImmutableList.of(new CriterionDTO(FieldName.SUBJECT.getValue(), Operator.CONTAINS.getValue(), SUBJECT)), Optional.empty()); private static final String SUBJECT_CONTAINS_IGNORE_CASE_FILE = "string_contains_ignore_case.json"; private static final QueryDTO SUBJECT_CONTAINS_IGNORE_CASE_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.SUBJECT.getValue(), Operator.CONTAINS_IGNORE_CASE.getValue(), SUBJECT))); + ImmutableList.of(new CriterionDTO(FieldName.SUBJECT.getValue(), Operator.CONTAINS_IGNORE_CASE.getValue(), SUBJECT)), Optional.empty()); private static final String SUBJECT_EQUALS_FILE = "string_equals.json"; private static final QueryDTO SUBJECT_EQUALS_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.SUBJECT.getValue(), Operator.EQUALS.getValue(), SUBJECT))); + ImmutableList.of(new CriterionDTO(FieldName.SUBJECT.getValue(), Operator.EQUALS.getValue(), SUBJECT)), Optional.empty()); private static final String SUBJECT_EQUALS_IGNORE_CASE_FILE = "string_equals_ignore_case.json"; private static final QueryDTO SUBJECT_EQUALS_IGNORE_CASE_DTO = new QueryDTO(AND, - ImmutableList.of(new CriterionDTO(FieldName.SUBJECT.getValue(), Operator.EQUALS_IGNORE_CASE.getValue(), SUBJECT))); + ImmutableList.of(new CriterionDTO(FieldName.SUBJECT.getValue(), Operator.EQUALS_IGNORE_CASE.getValue(), SUBJECT)), Optional.empty()); private static final TestId.Factory mailboxIdFactory = new TestId.Factory(); private static final QueryTranslator queryTranslator = new QueryTranslator(mailboxIdFactory); diff --git a/src/site/markdown/server/manage-webadmin.md b/src/site/markdown/server/manage-webadmin.md index 5ea35c2dd3..8c78ca3518 100644 --- a/src/site/markdown/server/manage-webadmin.md +++ b/src/site/markdown/server/manage-webadmin.md @@ -4267,6 +4267,15 @@ Messages in the Deleted Messages Vault of a specified user that are matched with "criteria": [] } ``` +- For limiting the number of restored messages, you can use the `limit` query property: + +``` +{ + "combinator": "and", + "limit": 99 + "criteria": [] +} +``` **Warning**: Current web-admin uses `US` locale as the default. Therefore, there might be some conflicts when using String `containsIgnoreCase` comparators to apply on the String data of other special locales stored in the Vault. More details at [JIRA](https://issues.apache.org/jira/browse/MAILBOX-384) --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org