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
The following commit(s) were added to refs/heads/master by this push: new c3150d0990 JAMES-3918 Force deletion of user mailboxes (#1608) c3150d0990 is described below commit c3150d09903a2acaa6c152c84552992708842f07 Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Tue Jun 27 07:08:52 2023 +0200 JAMES-3918 Force deletion of user mailboxes (#1608) --- .../docs/modules/ROOT/pages/operate/webadmin.adoc | 9 +++-- .../james/webadmin/routes/UserMailboxesRoutes.java | 23 +++++++---- .../webadmin/service/UserMailboxesService.java | 37 ++++++++++-------- .../webadmin/routes/UserMailboxesRoutesTest.java | 44 ++++++++++++++++++++-- src/site/markdown/server/manage-webadmin.md | 11 +++--- 5 files changed, 87 insertions(+), 37 deletions(-) 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 703169ee12..46c5d00439 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 @@ -1691,7 +1691,7 @@ Response codes: * 204: The mailbox now exists on the server * 400: Invalid mailbox name -* 404: The user name does not exist +* 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. To create nested mailboxes, for instance a work mailbox inside the INBOX mailbox, people should use the . separator. The sample query is: @@ -1713,7 +1713,7 @@ Response codes: * 204: The mailbox now does not exist on the server * 400: Invalid mailbox name -* 404: The user name does not exist +* 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. === Testing existence of a mailbox @@ -1747,7 +1747,8 @@ Resource name `usernameToBeUsed` should be an existing user Response codes: * 200: The mailboxes list was successfully retrieved -* 404: The user name does not exist +* 404: The user name does not exist, the mailbox does not exist. Note that this check can be bypassed by specifying the `force` query parameter. + === Deleting user mailboxes @@ -1760,7 +1761,7 @@ Resource name `usernameToBeUsed` should be an existing user Response codes: * 204: The user do not have mailboxes anymore -* 404: The user name does not exist +* 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. === Exporting user mailboxes 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 365c8e80d0..30c813fe1a 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 @@ -73,6 +73,13 @@ public class UserMailboxesRoutes implements Routes { return Username.of(request.params(USER_NAME)); } + private static UserMailboxesService.Options getOptions(Request request) { + if (request.queryParams().contains("force")) { + return UserMailboxesService.Options.Force; + } + return UserMailboxesService.Options.Check; + } + public static final String MAILBOX_NAME = ":mailboxName"; public static final String MAILBOXES = "mailboxes"; private static final String USER_NAME = ":userName"; @@ -134,7 +141,7 @@ public class UserMailboxesRoutes implements Routes { service.get(USER_MAILBOXES_BASE, (request, response) -> { response.status(HttpStatus.OK_200); try { - return userMailboxesService.listMailboxes(getUsernameParam(request)); + return userMailboxesService.listMailboxes(getUsernameParam(request), getOptions(request)); } catch (IllegalStateException e) { LOGGER.info("Invalid get on user mailboxes", e); throw ErrorResponder.builder() @@ -157,7 +164,7 @@ public class UserMailboxesRoutes implements Routes { public void defineDeleteUserMailbox() { service.delete(SPECIFIC_MAILBOX, (request, response) -> { try { - userMailboxesService.deleteMailbox(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME))); + userMailboxesService.deleteMailbox(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME)), getOptions(request)); return Responses.returnNoContent(response); } catch (IllegalStateException e) { LOGGER.info("Invalid delete on user mailbox", e); @@ -190,7 +197,7 @@ public class UserMailboxesRoutes implements Routes { public void defineDeleteUserMailboxes() { service.delete(USER_MAILBOXES_BASE, (request, response) -> { try { - userMailboxesService.deleteMailboxes(getUsernameParam(request)); + userMailboxesService.deleteMailboxes(getUsernameParam(request), getOptions(request)); return Responses.returnNoContent(response); } catch (IllegalStateException e) { LOGGER.info("Invalid delete on user mailboxes", e); @@ -207,7 +214,7 @@ public class UserMailboxesRoutes implements Routes { public void defineMailboxExists() { service.get(SPECIFIC_MAILBOX, (request, response) -> { try { - if (userMailboxesService.testMailboxExists(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME)))) { + if (userMailboxesService.testMailboxExists(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME)), getOptions(request))) { return Responses.returnNoContent(response); } else { throw ErrorResponder.builder() @@ -239,7 +246,7 @@ public class UserMailboxesRoutes implements Routes { public void defineCreateUserMailbox() { service.put(SPECIFIC_MAILBOX, (request, response) -> { try { - userMailboxesService.createMailbox(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME))); + userMailboxesService.createMailbox(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME)), getOptions(request)); return Responses.returnNoContent(response); } catch (IllegalStateException e) { LOGGER.info("Invalid put on user mailbox", e); @@ -264,7 +271,7 @@ public class UserMailboxesRoutes implements Routes { public void messageCount() { service.get(MESSAGE_COUNT_PATH, (request, response) -> { try { - return userMailboxesService.messageCount(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME))); + return userMailboxesService.messageCount(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME)), getOptions(request)); } catch (IllegalStateException | MailboxNotFoundException e) { LOGGER.info("Invalid get on user mailbox", e); throw ErrorResponder.builder() @@ -288,7 +295,7 @@ public class UserMailboxesRoutes implements Routes { public void unseenMessageCount() { service.get(UNSEEN_MESSAGE_COUNT_PATH, (request, response) -> { try { - return userMailboxesService.unseenMessageCount(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME))); + return userMailboxesService.unseenMessageCount(getUsernameParam(request), new MailboxName(request.params(MAILBOX_NAME)), getOptions(request)); } catch (IllegalStateException | MailboxNotFoundException e) { LOGGER.info("Invalid get on user mailbox", e); throw ErrorResponder.builder() @@ -313,7 +320,7 @@ public class UserMailboxesRoutes implements Routes { Username username = getUsernameParam(request); MailboxName mailboxName = new MailboxName(request.params(MAILBOX_NAME)); try { - userMailboxesService.usernamePreconditions(username); + userMailboxesService.usernamePreconditions(username, getOptions(request)); userMailboxesService.mailboxExistPreconditions(username, mailboxName); } catch (IllegalStateException e) { LOGGER.info("Invalid put on user mailbox", e); 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 e57048f5ac..6a0a120fad 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 @@ -56,6 +56,11 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; public class UserMailboxesService { + public enum Options { + Force, + Check + } + private static final Logger LOGGER = LoggerFactory.getLogger(UserMailboxesService.class); private final MailboxManager mailboxManager; @@ -67,8 +72,8 @@ public class UserMailboxesService { this.usersRepository = usersRepository; } - public void createMailbox(Username username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException { - usernamePreconditions(username); + public void createMailbox(Username username, MailboxName mailboxName, Options options) throws MailboxException, UsersRepositoryException { + usernamePreconditions(username, options); MailboxSession mailboxSession = mailboxManager.createSystemSession(username); try { MailboxPath mailboxPath = MailboxPath.forUser(username, mailboxName.asString()) @@ -80,8 +85,8 @@ public class UserMailboxesService { } } - public void deleteMailboxes(Username username) throws UsersRepositoryException { - usernamePreconditions(username); + public void deleteMailboxes(Username username, Options options) throws UsersRepositoryException { + usernamePreconditions(username, options); MailboxSession mailboxSession = mailboxManager.createSystemSession(username); listUserMailboxes(mailboxSession) .map(MailboxMetaData::getPath) @@ -89,8 +94,8 @@ public class UserMailboxesService { mailboxManager.endProcessingRequest(mailboxSession); } - public List<MailboxResponse> listMailboxes(Username username) throws UsersRepositoryException { - usernamePreconditions(username); + public List<MailboxResponse> listMailboxes(Username username, Options options) throws UsersRepositoryException { + usernamePreconditions(username, options); MailboxSession mailboxSession = mailboxManager.createSystemSession(username); try { return listUserMailboxes(mailboxSession) @@ -101,8 +106,8 @@ public class UserMailboxesService { } } - public boolean testMailboxExists(Username username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException { - usernamePreconditions(username); + public boolean testMailboxExists(Username username, MailboxName mailboxName, Options options) throws MailboxException, UsersRepositoryException { + usernamePreconditions(username, options); MailboxSession mailboxSession = mailboxManager.createSystemSession(username); MailboxPath mailboxPath = MailboxPath.forUser(username, mailboxName.asString()) .assertAcceptable(mailboxSession.getPathDelimiter()); @@ -142,8 +147,8 @@ public class UserMailboxesService { }); } - public void deleteMailbox(Username username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException, MailboxHaveChildrenException { - usernamePreconditions(username); + public void deleteMailbox(Username username, MailboxName mailboxName, Options options) throws MailboxException, UsersRepositoryException, MailboxHaveChildrenException { + usernamePreconditions(username, options); MailboxSession mailboxSession = mailboxManager.createSystemSession(username); MailboxPath mailboxPath = MailboxPath.forUser(username, mailboxName.asString()) .assertAcceptable(mailboxSession.getPathDelimiter()); @@ -152,8 +157,8 @@ public class UserMailboxesService { mailboxManager.endProcessingRequest(mailboxSession); } - public long messageCount(Username username, MailboxName mailboxName) throws UsersRepositoryException, MailboxException { - usernamePreconditions(username); + public long messageCount(Username username, MailboxName mailboxName, Options options) throws UsersRepositoryException, MailboxException { + usernamePreconditions(username, options); MailboxSession mailboxSession = mailboxManager.createSystemSession(username); try { return mailboxManager.getMailbox(MailboxPath.forUser(username, mailboxName.asString()), mailboxSession).getMessageCount(mailboxSession); @@ -162,8 +167,8 @@ public class UserMailboxesService { } } - public long unseenMessageCount(Username username, MailboxName mailboxName) throws UsersRepositoryException, MailboxException { - usernamePreconditions(username); + public long unseenMessageCount(Username username, MailboxName mailboxName, Options options) throws UsersRepositoryException, MailboxException { + usernamePreconditions(username, options); MailboxSession mailboxSession = mailboxManager.createSystemSession(username); try { return mailboxManager.getMailbox(MailboxPath.forUser(username, mailboxName.asString()), mailboxSession) @@ -188,8 +193,8 @@ public class UserMailboxesService { } } - public void usernamePreconditions(Username username) throws UsersRepositoryException { - Preconditions.checkState(usersRepository.contains(username), "User does not exist"); + public void usernamePreconditions(Username username, Options options) throws UsersRepositoryException { + Preconditions.checkState(options == Options.Force || usersRepository.contains(username), "User does not exist"); } public void mailboxExistPreconditions(Username username, MailboxName mailboxName) throws MailboxException { 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 3fa93a7d3e..bcfd26095d 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 @@ -270,7 +270,7 @@ class UserMailboxesRoutesTest { } @Test - void putShouldThrowWhenMailboxNameWithDots() throws Exception { + void putShouldThrowWhenMailboxNameWithDots() { Map<String, Object> errors = when() .put(MAILBOX_NAME_WITH_DOTS) .then() @@ -352,7 +352,7 @@ class UserMailboxesRoutesTest { when(usersRepository.contains(USERNAME)).thenReturn(false); Map<String, Object> errors = when() - .put(MAILBOX_NAME) + .delete(MAILBOX_NAME) .then() .statusCode(NOT_FOUND_404) .contentType(JSON) @@ -364,12 +364,36 @@ class UserMailboxesRoutesTest { assertThat(errors) .containsEntry("statusCode", NOT_FOUND_404) .containsEntry("type", ERROR_TYPE_NOTFOUND) - .containsEntry("message", "Invalid get on user mailboxes") + .containsEntry("message", "Invalid delete on user mailboxes") .containsEntry("details", "User does not exist"); } @Test - void getShouldReturnUserErrorWithInvalidWildcardMailboxName() throws Exception { + void putShouldReturn204WhenForceNonExistingUser() throws Exception { + when(usersRepository.contains(USERNAME)).thenReturn(false); + + given() + .queryParam("force") + .when() + .put(MAILBOX_NAME) + .then() + .statusCode(NO_CONTENT_204); + } + + @Test + void deleteShouldReturn204WhenForceNonExistingUser() throws Exception { + when(usersRepository.contains(USERNAME)).thenReturn(false); + + given() + .queryParam("force") + .when() + .delete(MAILBOX_NAME) + .then() + .statusCode(NO_CONTENT_204); + } + + @Test + void getShouldReturnUserErrorWithInvalidWildcardMailboxName() { Map<String, Object> errors = when() .get(MAILBOX_NAME + "*") .then() @@ -605,6 +629,18 @@ class UserMailboxesRoutesTest { .containsEntry("message", "Invalid delete on user mailboxes"); } + @Test + void deleteMailboxesShouldReturn204UserErrorWithNonExistingUser() throws Exception { + when(usersRepository.contains(USERNAME)).thenReturn(false); + + given() + .queryParam("force") + .when() + .delete() + .then() + .statusCode(NO_CONTENT_204); + } + @Test void getMailboxesShouldReturnEmptyListByDefault() { List<Object> list = diff --git a/src/site/markdown/server/manage-webadmin.md b/src/site/markdown/server/manage-webadmin.md index 9c76eb5ce0..48c5614a7d 100644 --- a/src/site/markdown/server/manage-webadmin.md +++ b/src/site/markdown/server/manage-webadmin.md @@ -1356,7 +1356,8 @@ by an admin to ensure Cassandra message consistency. - [Recomputing User JMAP fast message view projection](#Recomputing_User_JMAP_fast_message_view_projection) - [Counting emails](#Counting_emails) - [Counting unseen emails](#Couting_unseen_emails) - - [Clearing mailbox content][#Clearing_mailbox_content] + - [Clearing mailbox content][#Clearing_mailbox_content] + ### Creating a mailbox ``` @@ -1370,7 +1371,7 @@ Response codes: - 204: The mailbox now exists on the server - 400: Invalid mailbox name - - 404: The user name does not exist + - 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. To create nested mailboxes, for instance a work mailbox inside the INBOX mailbox, people should use the . separator. The sample query is: @@ -1391,7 +1392,7 @@ Response codes: - 204: The mailbox now does not exist on the server - 400: Invalid mailbox name - - 404: The user name does not exist + - 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. ### Testing existence of a mailbox @@ -1425,7 +1426,7 @@ Resource name `usernameToBeUsed` should be an existing user Response codes: - 200: The mailboxes list was successfully retrieved - - 404: The user name does not exist + - 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. ### Deleting user mailboxes @@ -1438,7 +1439,7 @@ Resource name `usernameToBeUsed` should be an existing user Response codes: - 204: The user do not have mailboxes anymore - - 404: The user name does not exist + - 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. ### Exporting user mailboxes --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org