This is an automated email from the ASF dual-hosted git repository. Arsnael pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 6e4318163b5c732ede1c9e3108ca1c2aa44008d1 Author: Rene Cordier <[email protected]> AuthorDate: Tue May 19 12:06:31 2026 +0700 JAMES-4204 Add a force parameter to restore backup webadmin route --- .../james/mailbox/backup/DefaultMailboxBackup.java | 48 ++++++++++++------ .../apache/james/mailbox/backup/MailboxBackup.java | 3 +- .../mailbox/backup/DefaultMailboxBackupTest.java | 58 ++++++++++++++++++++-- .../service/MailboxesRestoreRequestToTask.java | 6 ++- .../webadmin/service/MailboxesRestoreTask.java | 12 ++++- .../webadmin/service/MailboxesRestoreTaskDTO.java | 15 ++++-- .../james/webadmin/service/RestoreService.java | 49 ++++++++++++------ .../service/MailboxesRestoreRequestToTaskTest.java | 15 ++++-- .../james/webadmin/service/RestoreServiceTest.java | 35 +++++++++++++ .../test/resources/json/mailboxesRestore.task.json | 3 +- 10 files changed, 200 insertions(+), 44 deletions(-) diff --git a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/DefaultMailboxBackup.java b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/DefaultMailboxBackup.java index e8c964270b..f1a7acba1d 100644 --- a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/DefaultMailboxBackup.java +++ b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/DefaultMailboxBackup.java @@ -100,24 +100,17 @@ public class DefaultMailboxBackup implements MailboxBackup { mailboxManager.endProcessingRequest(session); } - private boolean isAccountNonEmpty(Username username) throws MailboxException { - MailboxSession session = mailboxManager.createSystemSession(username); - try { - return getAccountContentForUser(session) - .stream() - .findFirst() - .isPresent(); - } finally { - mailboxManager.endProcessingRequest(session); - } - } - @Override - public Publisher<BackupStatus> restore(Username username, InputStream source) { + public Publisher<BackupStatus> restore(Username username, InputStream source, boolean force) { try { if (isAccountNonEmpty(username)) { - LOGGER.warn("Warning, account should be empty before performing a restoration for user: {}", username); - return Mono.just(BackupStatus.NON_EMPTY_RECEIVER_ACCOUNT); + if (force) { + LOGGER.warn("Force restore: deleting existing mailbox data for user: {}", username); + clearAccountContent(username); + } else { + LOGGER.warn("Warning, account should be empty before performing a restoration for user: {}", username); + return Mono.just(BackupStatus.NON_EMPTY_RECEIVER_ACCOUNT); + } } } catch (Exception e) { LOGGER.error("Error during account restoration for user : " + username.asString(), e); @@ -132,6 +125,31 @@ public class DefaultMailboxBackup implements MailboxBackup { .onErrorReturn(BackupStatus.FAILED); } + private void clearAccountContent(Username username) throws MailboxException { + MailboxSession session = mailboxManager.createSystemSession(username); + try { + List<MailAccountContent> accountContents = getAccountContentForUser(session); + for (MailAccountContent content : accountContents) { + MailboxPath path = content.getMailboxWithAnnotations().mailbox.generateAssociatedPath(); + mailboxManager.deleteMailbox(path, session); + } + } finally { + mailboxManager.endProcessingRequest(session); + } + } + + private boolean isAccountNonEmpty(Username username) throws MailboxException { + MailboxSession session = mailboxManager.createSystemSession(username); + try { + return getAccountContentForUser(session) + .stream() + .findFirst() + .isPresent(); + } finally { + mailboxManager.endProcessingRequest(session); + } + } + private Stream<MailAccountContent> getMailboxWithAnnotationsFromPath(MailboxSession session, MailboxPath path) { try { MessageManager messageManager = mailboxManager.getMailbox(path, session); diff --git a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/MailboxBackup.java b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/MailboxBackup.java index 3b182833f3..4ac8622d11 100644 --- a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/MailboxBackup.java +++ b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/MailboxBackup.java @@ -42,8 +42,9 @@ public interface MailboxBackup { /** * @param username the user in which account the restored elements will be stored. * @param source the input stream to the archive containing the account elements. + * @param force if true, delete the user's existing mailbox data before restoring. * @return a Publisher indicating when the action is completed */ - Publisher<BackupStatus> restore(Username username, InputStream source) throws IOException, MailboxException; + Publisher<BackupStatus> restore(Username username, InputStream source, boolean force) throws IOException, MailboxException; } diff --git a/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/DefaultMailboxBackupTest.java b/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/DefaultMailboxBackupTest.java index c67f15b301..dd65a6c575 100644 --- a/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/DefaultMailboxBackupTest.java +++ b/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/DefaultMailboxBackupTest.java @@ -47,6 +47,7 @@ import reactor.core.publisher.Mono; class DefaultMailboxBackupTest implements MailboxMessageFixture { private static final int BUFFER_SIZE = 4096; + private static final boolean FORCE_RESTORE = true; private static final String EXPECTED_ANNOTATIONS_DIR = "annotations"; private final ArchiveService archiveService = new Zipper(); @@ -169,7 +170,7 @@ class DefaultMailboxBackupTest implements MailboxMessageFixture { backup.backupAccount(USERNAME_1, destination); InputStream source = new ByteArrayInputStream(destination.toByteArray()); - MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source)).block(); + MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source, !FORCE_RESTORE)).block(); assertThat(backupStatus).isEqualTo(MailboxBackup.BackupStatus.DONE); List<DefaultMailboxBackup.MailAccountContent> content = backup.getAccountContentForUser(sessionOtherUser); @@ -184,7 +185,7 @@ class DefaultMailboxBackupTest implements MailboxMessageFixture { backup.backupAccount(USERNAME_1, destination); InputStream source = new ByteArrayInputStream(destination.toByteArray()); - MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source)).block(); + MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source, !FORCE_RESTORE)).block(); assertThat(backupStatus).isEqualTo(MailboxBackup.BackupStatus.DONE); List<DefaultMailboxBackup.MailAccountContent> content = backup.getAccountContentForUser(sessionOtherUser); @@ -205,11 +206,33 @@ class DefaultMailboxBackupTest implements MailboxMessageFixture { backup.backupAccount(USERNAME_1, destination); InputStream source = new ByteArrayInputStream(destination.toByteArray()); - MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source)).block(); + MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source, !FORCE_RESTORE)).block(); assertThat(backupStatus).isEqualTo(MailboxBackup.BackupStatus.NON_EMPTY_RECEIVER_ACCOUNT); } + @Test + void restoringAccountInNonEmptyAccountWithForceShouldDeleteExistingAndRestore() throws Exception { + createMailbox(sessionUser, MAILBOX_PATH_USER1_MAILBOX1); + createMailbox(sessionOtherUser, MAILBOX_PATH_OTHER_USER_MAILBOX1); + + ByteArrayOutputStream destination = new ByteArrayOutputStream(BUFFER_SIZE); + backup.backupAccount(USERNAME_1, destination); + + InputStream source = new ByteArrayInputStream(destination.toByteArray()); + MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source, true)).block(); + + assertThat(backupStatus).isEqualTo(MailboxBackup.BackupStatus.DONE); + + List<DefaultMailboxBackup.MailAccountContent> content = backup.getAccountContentForUser(sessionOtherUser); + + assertThat(content).hasSize(1); + DefaultMailboxBackup.MailAccountContent mailAccountContent = content.get(0); + Mailbox mailbox = mailAccountContent.getMailboxWithAnnotations().mailbox; + assertThat(mailbox.getName()).isEqualTo(MAILBOX_1_NAME); + assertThat(mailAccountContent.getMessages().count()).isEqualTo(0); + } + @Test void backupAccountWithTwoMailboxesThenRestoringItInUser2AccountShouldCreateTwoMailboxes() throws Exception { createMailbox(sessionUser, MAILBOX_PATH_USER1_MAILBOX1); @@ -219,7 +242,7 @@ class DefaultMailboxBackupTest implements MailboxMessageFixture { backup.backupAccount(USERNAME_1, destination); InputStream source = new ByteArrayInputStream(destination.toByteArray()); - MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source)).block(); + MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source, !FORCE_RESTORE)).block(); assertThat(backupStatus).isEqualTo(MailboxBackup.BackupStatus.DONE); @@ -237,6 +260,33 @@ class DefaultMailboxBackupTest implements MailboxMessageFixture { assertThat(contentMailbox2.getMessages().count()).isEqualTo(0); } + @Test + void doRestoreWithTwoMailboxesAndOneMessageBackupShouldRestoreEntries() throws Exception { + ByteArrayOutputStream destination = new ByteArrayOutputStream(BUFFER_SIZE); + createMailboxWithMessages(sessionUser, MAILBOX_PATH_USER1_MAILBOX1, getMessage1AppendCommand()); + createMailboxWithMessages(sessionUser, MAILBOX_PATH_USER1_MAILBOX2, getMessage1AppendCommand()); + + backup.backupAccount(USERNAME_1, destination); + + InputStream source = new ByteArrayInputStream(destination.toByteArray()); + MailboxBackup.BackupStatus backupStatus = Mono.from(backup.restore(USERNAME_2, source, !FORCE_RESTORE)).block(); + + assertThat(backupStatus).isEqualTo(MailboxBackup.BackupStatus.DONE); + + List<DefaultMailboxBackup.MailAccountContent> content = backup.getAccountContentForUser(sessionOtherUser); + + assertThat(content).hasSize(2); + DefaultMailboxBackup.MailAccountContent contentMailbox1 = content.get(0); + Mailbox mailbox1 = contentMailbox1.getMailboxWithAnnotations().mailbox; + assertThat(mailbox1.getName()).isEqualTo(MAILBOX_1_NAME); + assertThat(contentMailbox1.getMessages().count()).isEqualTo(1); + + DefaultMailboxBackup.MailAccountContent contentMailbox2 = content.get(1); + Mailbox mailbox2 = contentMailbox2.getMailboxWithAnnotations().mailbox; + assertThat(mailbox2.getName()).isEqualTo(MAILBOX_2_NAME); + assertThat(contentMailbox2.getMessages().count()).isEqualTo(1); + } + private MessageManager.AppendCommand getMessage1AppendCommand() throws IOException { return MessageManager.AppendCommand.builder() .withFlags(flags1) diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreRequestToTask.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreRequestToTask.java index 0b95d3efe2..e8e25f8983 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreRequestToTask.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreRequestToTask.java @@ -19,6 +19,8 @@ package org.apache.james.webadmin.service; +import java.util.Optional; + import jakarta.inject.Inject; import org.apache.james.blob.api.BlobId; @@ -69,6 +71,8 @@ public class MailboxesRestoreRequestToTask extends TaskFromRequestRegistry.TaskR BlobId blobId = Mono.from(blobStore.save(blobStore.getDefaultBucketName(), data, BlobStore.StoragePolicy.LOW_COST)).block(); - return new MailboxesRestoreTask(restoreService, username, blobId); + Optional<Boolean> force = Optional.of(Boolean.parseBoolean(request.queryParams("force"))); + + return new MailboxesRestoreTask(restoreService, username, blobId, force); } } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreTask.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreTask.java index e7365e0b8d..a7a876fc98 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreTask.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreTask.java @@ -54,16 +54,22 @@ public class MailboxesRestoreTask implements Task { private final Username username; private final RestoreService service; private final BlobId blobId; + private final Optional<Boolean> force; MailboxesRestoreTask(RestoreService service, Username username, BlobId blobId) { + this(service, username, blobId, Optional.of(false)); + } + + MailboxesRestoreTask(RestoreService service, Username username, BlobId blobId, Optional<Boolean> force) { this.username = username; this.service = service; this.blobId = blobId; + this.force = force; } @Override public Result run() { - return service.restore(username, blobId) + return service.restore(username, blobId, force.orElse(false)) .block(); } @@ -80,6 +86,10 @@ public class MailboxesRestoreTask implements Task { return blobId; } + public Optional<Boolean> isForce() { + return force; + } + @Override public Optional<TaskExecutionDetails.AdditionalInformation> details() { return Optional.of(new AdditionalInformation(username, diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreTaskDTO.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreTaskDTO.java index 1307e53250..2fb54397f9 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreTaskDTO.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesRestoreTaskDTO.java @@ -21,6 +21,8 @@ package org.apache.james.webadmin.service; import static org.apache.james.webadmin.service.MailboxesRestoreTask.TASK_TYPE; +import java.util.Optional; + import org.apache.james.blob.api.BlobId; import org.apache.james.core.Username; import org.apache.james.json.DTOModule; @@ -33,13 +35,16 @@ public class MailboxesRestoreTaskDTO implements TaskDTO { private final String type; private final String username; private final String blobId; + private final Optional<Boolean> force; public MailboxesRestoreTaskDTO(@JsonProperty("type") String type, @JsonProperty("username") String username, - @JsonProperty("blobId") String blobId) { + @JsonProperty("blobId") String blobId, + @JsonProperty("force") Optional<Boolean> force) { this.type = type; this.username = username; this.blobId = blobId; + this.force = force; } @Override @@ -55,6 +60,10 @@ public class MailboxesRestoreTaskDTO implements TaskDTO { return blobId; } + public Optional<Boolean> getForce() { + return force; + } + public static TaskDTOModule<MailboxesRestoreTask, MailboxesRestoreTaskDTO> module(RestoreService service, BlobId.Factory blobIdFactory) { return DTOModule .forDomainObject(MailboxesRestoreTask.class) @@ -66,10 +75,10 @@ public class MailboxesRestoreTaskDTO implements TaskDTO { } public MailboxesRestoreTask fromDTO(RestoreService service, BlobId.Factory blobIdFactory) { - return new MailboxesRestoreTask(service, Username.of(username), blobIdFactory.of(blobId)); + return new MailboxesRestoreTask(service, Username.of(username), blobIdFactory.parse(blobId), force); } public static MailboxesRestoreTaskDTO toDTO(MailboxesRestoreTask domainObject, String typeName) { - return new MailboxesRestoreTaskDTO(typeName, domainObject.getUsername().asString(), domainObject.getBlobId().asString()); + return new MailboxesRestoreTaskDTO(typeName, domainObject.getUsername().asString(), domainObject.getBlobId().asString(), domainObject.isForce()); } } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/RestoreService.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/RestoreService.java index 54c47188bf..b2b42e5b27 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/RestoreService.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/RestoreService.java @@ -19,6 +19,7 @@ package org.apache.james.webadmin.service; +import java.io.IOException; import java.io.InputStream; import jakarta.inject.Inject; @@ -47,26 +48,44 @@ public class RestoreService { } public Mono<Task.Result> restore(Username username, BlobId blobId) { - try (InputStream inputStream = blobStore.read(blobStore.getDefaultBucketName(), blobId)) { - return restore(username, inputStream); - } catch (Exception e) { - LOGGER.error("Error restoring mailboxes for user {}", username.asString(), e); - return Mono.just(Task.Result.PARTIAL); - } finally { - try { - Mono.from(blobStore.delete(blobStore.getDefaultBucketName(), blobId)).block(); - } catch (Exception e) { - LOGGER.error("Error deleting blob {} after restore", blobId.asString(), e); - } + return restore(username, blobId, false); + } + + public Mono<Task.Result> restore(Username username, BlobId blobId, boolean force) { + return Mono.fromCallable(() -> blobStore.read(blobStore.getDefaultBucketName(), blobId)) + .flatMap(inputStream -> { + try { + return Mono.from(mailboxBackup.restore(username, inputStream, force)) + .map(this::computeTaskResult) + .doFinally(signalType -> { + closeStream(inputStream); + deleteBlob(blobId); + }); + } catch (Exception e) { + closeStream(inputStream); + deleteBlob(blobId); + return Mono.error(e); + } + }) + .onErrorResume(e -> { + LOGGER.error("Error restoring mailboxes for user {}", username.asString(), e); + return Mono.just(Task.Result.PARTIAL); + }); + } + + private void closeStream(InputStream inputStream) { + try { + inputStream.close(); + } catch (IOException e) { + LOGGER.error("Error closing input stream after restore", e); } } - private Mono<Task.Result> restore(Username username, InputStream source) { + private void deleteBlob(BlobId blobId) { try { - return Mono.from(mailboxBackup.restore(username, source)) - .map(this::computeTaskResult); + Mono.from(blobStore.delete(blobStore.getDefaultBucketName(), blobId)).block(); } catch (Exception e) { - return Mono.error(e); + LOGGER.error("Error deleting blob {} after restore", blobId.asString(), e); } } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesRestoreRequestToTaskTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesRestoreRequestToTaskTest.java index 72ba4ef92f..e80c44b944 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesRestoreRequestToTaskTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesRestoreRequestToTaskTest.java @@ -28,9 +28,7 @@ import static org.hamcrest.Matchers.notNullValue; import java.io.ByteArrayOutputStream; import java.util.zip.ZipOutputStream; -import org.apache.james.blob.api.BlobId; import org.apache.james.blob.api.BlobStore; -import org.apache.james.blob.api.PlainBlobId; import org.apache.james.blob.export.file.FileSystemExtension; import org.apache.james.filesystem.api.FileSystem; import org.apache.james.json.DTOConverter; @@ -87,7 +85,6 @@ class MailboxesRestoreRequestToTaskTest { } private static final String BASE_PATH = "users/:username/mailboxes"; - private static final BlobId.Factory BLOB_ID_FACTORY = new PlainBlobId.Factory(); private WebAdminServer webAdminServer; private MemoryTaskManager taskManager; @@ -215,6 +212,18 @@ class MailboxesRestoreRequestToTaskTest { .body("taskId", is(notNullValue())); } + @Test + void postShouldCreateANewTaskWithForceTrue() throws Exception { + given() + .queryParam("task", "restore") + .queryParam("force", "true") + .body(emptyZip()) + .post() + .then() + .statusCode(HttpStatus.CREATED_201) + .body("taskId", is(notNullValue())); + } + @Test void restoreMailboxesShouldCompleteWhenUserHasNoMailbox() throws Exception { String taskId = given() diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/RestoreServiceTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/RestoreServiceTest.java index a983e1382e..5eab10a74e 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/RestoreServiceTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/RestoreServiceTest.java @@ -115,6 +115,41 @@ class RestoreServiceTest { .isEqualTo(Task.Result.PARTIAL); } + @Test + void restoreWithForceShouldReturnCompleteWhenNonEmptyAccount() throws Exception { + createAMailboxWithAMail(); + + ByteArrayOutputStream destination = new ByteArrayOutputStream(BUFFER_SIZE); + testSystem.backup.backupAccount(BOB, destination); + + InputStream source = new ByteArrayInputStream(destination.toByteArray()); + BlobId blobId = Mono.from(testSystem.blobStore.save(testSystem.blobStore.getDefaultBucketName(), source, BlobStore.StoragePolicy.LOW_COST)).block(); + + assertThat(testee.restore(BOB, blobId, true).block()) + .isEqualTo(Task.Result.COMPLETED); + } + + @Test + void restoreWithForceShouldDeleteExistingAndRestoreContent() throws Exception { + createAMailboxWithAMail(); + + ByteArrayOutputStream destination = new ByteArrayOutputStream(BUFFER_SIZE); + testSystem.backup.backupAccount(BOB, destination); + + InputStream source = new ByteArrayInputStream(destination.toByteArray()); + BlobId blobId = Mono.from(testSystem.blobStore.save(testSystem.blobStore.getDefaultBucketName(), source, BlobStore.StoragePolicy.LOW_COST)).block(); + + testee.restore(BOB, blobId, true).block(); + + MailboxSession bobSession = testSystem.mailboxManager.createSystemSession(BOB); + MessageManager mailbox = testSystem.mailboxManager.getMailbox(MailboxPath.inbox(BOB), bobSession); + MessageResultIterator resultIterator = mailbox.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, bobSession); + assertThat(resultIterator).toIterable() + .hasSize(1) + .first() + .satisfies(result -> assertThat(new String(result.getFullContent().getInputStream().readAllBytes())).isEqualTo(MESSAGE_CONTENT)); + } + @Test void restoreShouldReturnPartialWhenFailed() throws Exception { doThrow(new RuntimeException()) diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesRestore.task.json b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesRestore.task.json index c19fc26185..92d960bd3e 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesRestore.task.json +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesRestore.task.json @@ -1,5 +1,6 @@ { "type":"MailboxesRestoreTask", "username": "bob", - "blobId": "abc123" + "blobId": "abc123", + "force": false } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
