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 d5bab2ab6347eb42d5ed66436270f77a59f5442f Author: Tung TRAN <[email protected]> AuthorDate: Tue Aug 3 18:07:30 2021 +0700 JAMES-3621 Mailbox webadmin - Clearing content of mailbox - Route --- .../WebadminMailboxTaskSerializationModule.java | 8 + .../james/webadmin/routes/UserMailboxesRoutes.java | 43 +++++ .../webadmin/service/UserMailboxesService.java | 10 +- .../webadmin/routes/UserMailboxesRoutesTest.java | 192 ++++++++++++++++++++- 4 files changed, 251 insertions(+), 2 deletions(-) diff --git a/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/WebadminMailboxTaskSerializationModule.java b/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/WebadminMailboxTaskSerializationModule.java index 369949d..e9010a2 100644 --- a/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/WebadminMailboxTaskSerializationModule.java +++ b/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/WebadminMailboxTaskSerializationModule.java @@ -30,6 +30,7 @@ import org.apache.james.server.task.json.dto.TaskDTOModule; import org.apache.james.task.Task; import org.apache.james.task.TaskExecutionDetails; import org.apache.james.webadmin.dto.DTOModuleInjections; +import org.apache.james.webadmin.service.ClearMailboxContentTaskAdditionalInformationDTO; import org.apache.james.webadmin.service.CreateMissingParentsTask; import org.apache.james.webadmin.service.CreateMissingParentsTaskAdditionalInformationDTO; import org.apache.james.webadmin.service.EventDeadLettersRedeliverAllTaskDTO; @@ -140,4 +141,11 @@ public class WebadminMailboxTaskSerializationModule extends AbstractModule { public AdditionalInformationDTOModule<? extends TaskExecutionDetails.AdditionalInformation, ? extends AdditionalInformationDTO> webAdminCreateMissingParentsAdditionalInformation() { return CreateMissingParentsTaskAdditionalInformationDTO.SERIALIZATION_MODULE; } + + @Named(DTOModuleInjections.WEBADMIN_DTO) + @ProvidesIntoSet + public AdditionalInformationDTOModule<? extends TaskExecutionDetails.AdditionalInformation, ? extends AdditionalInformationDTO> webAdminClearMailboxContentAdditionalInformation() { + return ClearMailboxContentTaskAdditionalInformationDTO.SERIALIZATION_MODULE; + } + } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java index 092c2c6..46746ed 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserMailboxesRoutes.java @@ -35,13 +35,18 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import org.apache.james.core.Username; +import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.exception.MailboxNameException; import org.apache.james.mailbox.exception.MailboxNotFoundException; import org.apache.james.mailbox.indexer.ReIndexer; +import org.apache.james.task.Task; import org.apache.james.task.TaskManager; +import org.apache.james.user.api.UsersRepositoryException; import org.apache.james.webadmin.Constants; import org.apache.james.webadmin.Routes; +import org.apache.james.webadmin.service.ClearMailboxContentTask; import org.apache.james.webadmin.service.UserMailboxesService; +import org.apache.james.webadmin.tasks.TaskFromRequest; import org.apache.james.webadmin.tasks.TaskFromRequestRegistry; import org.apache.james.webadmin.tasks.TaskFromRequestRegistry.TaskRegistration; import org.apache.james.webadmin.tasks.TaskIdDto; @@ -92,6 +97,7 @@ public class UserMailboxesRoutes implements Routes { public static final String SPECIFIC_MAILBOX = USER_MAILBOXES_BASE + Constants.SEPARATOR + MAILBOX_NAME; public static final String MESSAGE_COUNT_PATH = SPECIFIC_MAILBOX + "/messageCount"; public static final String UNSEEN_MESSAGE_COUNT_PATH = SPECIFIC_MAILBOX + "/unseenMessageCount"; + public static final String MESSAGES_PATH = SPECIFIC_MAILBOX + "/messages"; private final UserMailboxesService userMailboxesService; private final JsonTransformer jsonTransformer; @@ -135,6 +141,9 @@ public class UserMailboxesRoutes implements Routes { .ifPresent(route -> service.post(USER_MAILBOXES_BASE, route, jsonTransformer)); unseenMessageCount(); + + TaskFromRequest clearMailboxContentTaskRequest = this::clearMailboxContent; + service.delete(MESSAGES_PATH, clearMailboxContentTaskRequest.asRoute(taskManager), jsonTransformer); } @GET @@ -425,4 +434,38 @@ public class UserMailboxesRoutes implements Routes { } }); } + + @DELETE + @Path("/{mailboxName}/messages") + @ApiOperation(value = "Clearing content of a given mailbox.", nickname = "ClearMailboxContent") + @ApiImplicitParams({ + @ApiImplicitParam(required = true, dataType = "string", name = "username", paramType = "path"), + @ApiImplicitParam(required = true, dataType = "string", name = "mailboxName", paramType = "path") + }) + @ApiResponses( + { + @ApiResponse(code = HttpStatus.CREATED_201, message = "The taskId of the given scheduled task", response = TaskIdDto.class), + @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Invalid mailbox name"), + @ApiResponse(code = HttpStatus.UNAUTHORIZED_401, message = "Unauthorized. The user is not authenticated on the platform"), + @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "Invalid get on user mailboxes. The `username` or `mailboxName` does not exit"), + }) + + public Task clearMailboxContent(Request request) throws UsersRepositoryException, MailboxException { + Username username = getUsernameParam(request); + MailboxName mailboxName = new MailboxName(request.params(MAILBOX_NAME)); + try { + userMailboxesService.usernamePreconditions(username); + userMailboxesService.mailboxExistPreconditions(username, mailboxName); + } catch (IllegalStateException e) { + LOGGER.info("Invalid put on user mailbox", e); + throw ErrorResponder.builder() + .statusCode(HttpStatus.NOT_FOUND_404) + .type(ErrorType.NOT_FOUND) + .message("Invalid get on user mailboxes") + .cause(e) + .haltError(); + } + + return new ClearMailboxContentTask(username, mailboxName, userMailboxesService); + } } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java index dde29fe..f88c4c7 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java @@ -172,10 +172,18 @@ public class UserMailboxesService { } } - private void usernamePreconditions(Username username) throws UsersRepositoryException { + public void usernamePreconditions(Username username) throws UsersRepositoryException { Preconditions.checkState(usersRepository.contains(username), "User does not exist"); } + public void mailboxExistPreconditions(Username username, MailboxName mailboxName) throws MailboxException { + MailboxSession mailboxSession = mailboxManager.createSystemSession(username); + MailboxPath mailboxPath = MailboxPath.forUser(username, mailboxName.asString()) + .assertAcceptable(mailboxSession.getPathDelimiter()); + Preconditions.checkState(Boolean.TRUE.equals(Mono.from(mailboxManager.mailboxExists(mailboxPath, mailboxSession)).block()), + "Mailbox does not exist. " + mailboxPath.asString()); + } + private Stream<MailboxMetaData> listUserMailboxes(MailboxSession mailboxSession) throws MailboxException { return mailboxManager.search( MailboxQuery.privateMailboxesBuilder(mailboxSession).build(), diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java index 4fc7201..53fcf6e 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java @@ -28,6 +28,7 @@ import static org.apache.james.webadmin.Constants.SEPARATOR; import static org.apache.james.webadmin.routes.UserMailboxesRoutes.USERS_BASE; import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.jetty.http.HttpStatus.BAD_REQUEST_400; +import static org.eclipse.jetty.http.HttpStatus.CREATED_201; import static org.eclipse.jetty.http.HttpStatus.INTERNAL_SERVER_ERROR_500; import static org.eclipse.jetty.http.HttpStatus.NOT_FOUND_404; import static org.eclipse.jetty.http.HttpStatus.NO_CONTENT_204; @@ -108,6 +109,8 @@ import org.apache.james.user.api.UsersRepositoryException; import org.apache.james.webadmin.WebAdminServer; import org.apache.james.webadmin.WebAdminUtils; import org.apache.james.webadmin.dto.WebAdminUserReindexingTaskAdditionalInformationDTO; +import org.apache.james.webadmin.service.ClearMailboxContentTask; +import org.apache.james.webadmin.service.ClearMailboxContentTaskAdditionalInformationDTO; import org.apache.james.webadmin.service.UserMailboxesService; import org.apache.james.webadmin.utils.JsonTransformer; import org.apache.mailbox.tools.indexer.ReIndexerImpl; @@ -170,7 +173,8 @@ class UserMailboxesRoutesTest { taskManager, ImmutableSet.of(new UserMailboxesRoutes.UserReIndexingTaskRegistration(reIndexer))), new TasksRoutes(taskManager, new JsonTransformer(), - DTOConverter.of(WebAdminUserReindexingTaskAdditionalInformationDTO.serializationModule(mailboxIdFactory)))) + DTOConverter.of(WebAdminUserReindexingTaskAdditionalInformationDTO.serializationModule(mailboxIdFactory), + ClearMailboxContentTaskAdditionalInformationDTO.SERIALIZATION_MODULE))) .start(); RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer) @@ -1114,6 +1118,63 @@ class UserMailboxesRoutesTest { .containsEntry("message", "Invalid get on user mailboxes") .containsEntry("details", String.format("#private:%s:%s can not be found", USERNAME.asString(), MAILBOX_NAME)); } + + @Test + void deleteMailboxContentShouldReturnErrorWhenUserIsNotFound() throws UsersRepositoryException { + when(usersRepository.contains(USERNAME)).thenReturn(false); + + Map<String, Object> errors = when() + .delete(MAILBOX_NAME + "/messages") + .then() + .statusCode(NOT_FOUND_404) + .contentType(JSON) + .extract() + .body() + .jsonPath() + .getMap("."); + + assertThat(errors) + .containsEntry("statusCode", NOT_FOUND_404) + .containsEntry("type", ERROR_TYPE_NOTFOUND) + .containsEntry("message", "Invalid get on user mailboxes") + .containsEntry("details", "User does not exist"); + } + + @Test + void deleteMailboxContentShouldReturnErrorWhenMailboxDoesNotExist() { + Map<String, Object> errors = when() + .delete(MAILBOX_NAME + "/messages") + .then() + .statusCode(NOT_FOUND_404) + .contentType(JSON) + .extract() + .body() + .jsonPath() + .getMap("."); + + assertThat(errors) + .containsEntry("statusCode", NOT_FOUND_404) + .containsEntry("type", ERROR_TYPE_NOTFOUND) + .containsEntry("message", "Invalid get on user mailboxes") + .containsEntry("details", String.format("Mailbox does not exist. #private:%s:%s", USERNAME.asString(), MAILBOX_NAME)); + } + + @Test + void deleteMailboxContentShouldReturnTaskId() { + with() + .put(MAILBOX_NAME); + + String taskId = when() + .delete(MAILBOX_NAME + "/messages") + .then() + .statusCode(CREATED_201) + .extract() + .jsonPath() + .get("taskId"); + + assertThat(taskId) + .isNotEmpty(); + } } @Nested @@ -1804,6 +1865,135 @@ class UserMailboxesRoutesTest { assertThat(searchIndex.retrieveIndexedFlags(mailbox, uid).blockOptional()) .isEmpty(); } + + @Test + void userReprocessingShouldReturnTaskDetailWhenDeleteMailboxContentWithNoEmail() { + with() + .put(MAILBOX_NAME); + + String taskId = when() + .delete(MAILBOX_NAME + "/messages") + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", Matchers.is("completed")) + .body("taskId", Matchers.is(notNullValue())) + .body("type", Matchers.is(ClearMailboxContentTask.TASK_TYPE.asString())) + .body("startedDate", Matchers.is(notNullValue())) + .body("submitDate", Matchers.is(notNullValue())) + .body("completedDate", Matchers.is(notNullValue())) + .body("additionalInformation.username", Matchers.is(USERNAME.asString())) + .body("additionalInformation.mailboxName", Matchers.is(MAILBOX_NAME)) + .body("additionalInformation.messagesSuccessCount", Matchers.is(0)) + .body("additionalInformation.messagesFailCount", Matchers.is(0)); + } + + @Test + void userReprocessingShouldReturnTaskDetailWhenDeleteMailboxContentWithHasEmails() { + with() + .put(MAILBOX_NAME); + + MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, MAILBOX_NAME); + MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME); + + IntStream.range(0, 10) + .forEach(index -> { + try { + mailboxManager.getMailbox(mailboxPath, systemSession) + .appendMessage( + MessageManager.AppendCommand.builder() + .build("header: value\r\n\r\nbody"), + systemSession); + } catch (MailboxException e) { + LOGGER.warn("Error when append message " + e); + } + }); + + String taskId = when() + .delete(MAILBOX_NAME + "/messages") + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", Matchers.is("completed")) + .body("taskId", Matchers.is(notNullValue())) + .body("type", Matchers.is(ClearMailboxContentTask.TASK_TYPE.asString())) + .body("startedDate", Matchers.is(notNullValue())) + .body("submitDate", Matchers.is(notNullValue())) + .body("completedDate", Matchers.is(notNullValue())) + .body("additionalInformation.username", Matchers.is(USERNAME.asString())) + .body("additionalInformation.mailboxName", Matchers.is(MAILBOX_NAME)) + .body("additionalInformation.messagesSuccessCount", Matchers.is(10)) + .body("additionalInformation.messagesFailCount", Matchers.is(0)); + } + + @Test + void userReprocessingShouldEmptyMailboxWhenDeleteMailboxContent() throws MailboxException { + with() + .put(MAILBOX_NAME); + + MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, MAILBOX_NAME); + MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME); + + mailboxManager.getMailbox(mailboxPath, systemSession) + .appendMessage( + MessageManager.AppendCommand.builder() + .build("header: value\r\n\r\nbody"), + systemSession); + + String taskId = when() + .delete(MAILBOX_NAME + "/messages") + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await"); + + assertThat(mailboxManager.getMailbox(mailboxPath, systemSession).getMailboxCounters(systemSession).getCount()) + .isEqualTo(0); + } + + @Test + void userReprocessingShouldNotClearUnRelatedMailboxWhenDeleteMailboxContent() throws MailboxException { + with() + .put(MAILBOX_NAME); + + String unRelatedMailbox = "unRelatedMailbox"; + with() + .put(unRelatedMailbox); + MailboxPath mailboxPath = MailboxPath.forUser(USERNAME, unRelatedMailbox); + MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME); + + mailboxManager.getMailbox(mailboxPath, systemSession) + .appendMessage( + MessageManager.AppendCommand.builder() + .build("header: value\r\n\r\nbody"), + systemSession); + + String taskId = when() + .delete(MAILBOX_NAME + "/messages") + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await"); + + assertThat(mailboxManager.getMailbox(mailboxPath, systemSession).getMailboxCounters(systemSession).getCount()) + .isEqualTo(1); + } } @Nested --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
