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 92750e2165cd5c51dd412da877da3b90d6d8c664
Author: Rémi KOWALSKI <[email protected]>
AuthorDate: Wed Nov 6 15:06:25 2019 +0100

    JAMES-2964 forbid to create quotas with negative number
---
 .../org/apache/james/core/quota/QuotaCount.java    |  2 +
 .../org/apache/james/core/quota/QuotaSize.java     |  2 +
 .../org/apache/james/core/quota/QuotaValue.java    |  6 ++
 .../org/apache/james/webadmin/dto/QuotaDTO.java    | 21 ++---
 .../apache/james/webadmin/dto/QuotaDetailsDTO.java | 36 ++++----
 .../apache/james/webadmin/dto/QuotaDomainDTO.java  | 26 +++---
 .../dto/{QuotaDTO.java => ValidatedQuotaDTO.java}  | 15 ++--
 .../james/webadmin/routes/DomainQuotaRoutes.java   | 44 ++++------
 .../james/webadmin/routes/GlobalQuotaRoutes.java   | 15 ++--
 .../james/webadmin/routes/UserQuotaRoutes.java     | 22 ++++-
 .../james/webadmin/service/DomainQuotaService.java | 10 +--
 .../james/webadmin/service/GlobalQuotaService.java |  8 +-
 .../james/webadmin/service/UserQuotaService.java   | 12 +--
 .../webadmin/validation/QuotaDTOValidator.java     | 70 ++++++++++++++++
 .../webadmin/dto/QuotaValueDeserializerTest.java   |  4 +-
 .../webadmin/routes/DomainQuotaRoutesTest.java     | 73 ++++++++++++++++
 .../webadmin/routes/GlobalQuotaRoutesTest.java     | 80 ++++++++++++++++++
 .../james/webadmin/routes/UserQuotaRoutesTest.java | 97 +++++++++++++++++++++-
 18 files changed, 436 insertions(+), 107 deletions(-)

diff --git a/core/src/main/java/org/apache/james/core/quota/QuotaCount.java 
b/core/src/main/java/org/apache/james/core/quota/QuotaCount.java
index eef03fa..0eb6915 100644
--- a/core/src/main/java/org/apache/james/core/quota/QuotaCount.java
+++ b/core/src/main/java/org/apache/james/core/quota/QuotaCount.java
@@ -22,6 +22,7 @@ import java.util.Optional;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
 
 public class QuotaCount implements QuotaValue<QuotaCount> {
 
@@ -40,6 +41,7 @@ public class QuotaCount implements QuotaValue<QuotaCount> {
     private final Optional<Long> value;
 
     private QuotaCount(Optional<Long> value) {
+        Preconditions.checkArgument(QuotaValue.isValidValue(value), "Quota 
limit should be positive");
         this.value = value;
     }
 
diff --git a/core/src/main/java/org/apache/james/core/quota/QuotaSize.java 
b/core/src/main/java/org/apache/james/core/quota/QuotaSize.java
index 6d1f2ac..22d788f 100644
--- a/core/src/main/java/org/apache/james/core/quota/QuotaSize.java
+++ b/core/src/main/java/org/apache/james/core/quota/QuotaSize.java
@@ -22,6 +22,7 @@ import java.util.Optional;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
 
 public class QuotaSize implements QuotaValue<QuotaSize> {
 
@@ -42,6 +43,7 @@ public class QuotaSize implements QuotaValue<QuotaSize> {
     private final Optional<Long> value;
 
     private QuotaSize(Optional<Long> value) {
+        Preconditions.checkArgument(QuotaValue.isValidValue(value), "Quota 
limit should be positive");
         this.value = value;
     }
 
diff --git a/core/src/main/java/org/apache/james/core/quota/QuotaValue.java 
b/core/src/main/java/org/apache/james/core/quota/QuotaValue.java
index f4342d3..4f07eec 100644
--- a/core/src/main/java/org/apache/james/core/quota/QuotaValue.java
+++ b/core/src/main/java/org/apache/james/core/quota/QuotaValue.java
@@ -18,8 +18,14 @@
  ****************************************************************/
 package org.apache.james.core.quota;
 
+import java.util.Optional;
+
 public interface QuotaValue<T extends QuotaValue<T>> {
 
+    static boolean isValidValue(Optional<Long> value) {
+        return !value.isPresent() || value.get() >= 0;
+    }
+
     long asLong();
 
     boolean isLimited();
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
index 9a02cc6..f7a1ba7 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
@@ -23,9 +23,6 @@ package org.apache.james.webadmin.dto;
 import java.util.Objects;
 import java.util.Optional;
 
-import org.apache.james.core.quota.QuotaCount;
-import org.apache.james.core.quota.QuotaSize;
-
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
 import com.google.common.base.MoreObjects;
@@ -39,20 +36,20 @@ public class QuotaDTO {
 
     @JsonPOJOBuilder(withPrefix = "")
     public static class Builder {
-        private Optional<QuotaCount> count;
-        private Optional<QuotaSize> size;
+        private Optional<Long> count;
+        private Optional<Long> size;
 
         private Builder() {
             count = Optional.empty();
             size = Optional.empty();
         }
 
-        public Builder count(Optional<QuotaCount> count) {
+        public Builder count(Optional<Long> count) {
             this.count = count;
             return this;
         }
 
-        public Builder size(Optional<QuotaSize> size) {
+        public Builder size(Optional<Long> size) {
             this.size = size;
             return this;
         }
@@ -62,19 +59,19 @@ public class QuotaDTO {
         }
     }
 
-    private final Optional<QuotaCount> count;
-    private final Optional<QuotaSize> size;
+    private final Optional<Long> count;
+    private final Optional<Long> size;
 
-    private QuotaDTO(Optional<QuotaCount> count, Optional<QuotaSize> size) {
+    private QuotaDTO(Optional<Long> count, Optional<Long> size) {
         this.count = count;
         this.size = size;
     }
 
-    public Optional<QuotaCount> getCount() {
+    public Optional<Long> getCount() {
         return count;
     }
 
-    public Optional<QuotaSize> getSize() {
+    public Optional<Long> getSize() {
         return size;
     }
 
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDetailsDTO.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDetailsDTO.java
index 9042122..7449c90 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDetailsDTO.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDetailsDTO.java
@@ -35,10 +35,10 @@ public class QuotaDetailsDTO {
     }
 
     public static class Builder {
-        private Optional<QuotaDTO> global;
-        private Optional<QuotaDTO> domain;
-        private Optional<QuotaDTO> user;
-        private Optional<QuotaDTO> computed;
+        private Optional<ValidatedQuotaDTO> global;
+        private Optional<ValidatedQuotaDTO> domain;
+        private Optional<ValidatedQuotaDTO> user;
+        private Optional<ValidatedQuotaDTO> computed;
         private OccupationDTO occupation;
 
         private Builder() {
@@ -47,22 +47,22 @@ public class QuotaDetailsDTO {
             computed = Optional.empty();
         }
 
-        public Builder global(QuotaDTO global) {
+        public Builder global(ValidatedQuotaDTO global) {
             this.global = Optional.of(global);
             return this;
         }
 
-        public Builder domain(QuotaDTO domain) {
+        public Builder domain(ValidatedQuotaDTO domain) {
             this.domain = Optional.of(domain);
             return this;
         }
 
-        public Builder user(QuotaDTO user) {
+        public Builder user(ValidatedQuotaDTO user) {
             this.user = Optional.of(user);
             return this;
         }
 
-        public Builder computed(QuotaDTO computed) {
+        public Builder computed(ValidatedQuotaDTO computed) {
             this.computed = Optional.of(computed);
             return this;
         }
@@ -72,7 +72,7 @@ public class QuotaDetailsDTO {
             return this;
         }
 
-        public Builder valueForScope(Quota.Scope scope, QuotaDTO value) {
+        public Builder valueForScope(Quota.Scope scope, ValidatedQuotaDTO 
value) {
             switch (scope) {
                 case Global:
                     return global(value);
@@ -90,13 +90,13 @@ public class QuotaDetailsDTO {
         }
     }
 
-    private final Optional<QuotaDTO> global;
-    private final Optional<QuotaDTO> domain;
-    private final Optional<QuotaDTO> user;
-    private final Optional<QuotaDTO> computed;
+    private final Optional<ValidatedQuotaDTO> global;
+    private final Optional<ValidatedQuotaDTO> domain;
+    private final Optional<ValidatedQuotaDTO> user;
+    private final Optional<ValidatedQuotaDTO> computed;
     private final OccupationDTO occupation;
 
-    private QuotaDetailsDTO(Optional<QuotaDTO> global, Optional<QuotaDTO> 
domain, Optional<QuotaDTO> user, Optional<QuotaDTO> computed, OccupationDTO 
occupation) {
+    private QuotaDetailsDTO(Optional<ValidatedQuotaDTO> global, 
Optional<ValidatedQuotaDTO> domain, Optional<ValidatedQuotaDTO> user, 
Optional<ValidatedQuotaDTO> computed, OccupationDTO occupation) {
         this.global = global;
         this.domain = domain;
         this.user = user;
@@ -104,19 +104,19 @@ public class QuotaDetailsDTO {
         this.occupation = occupation;
     }
 
-    public Optional<QuotaDTO> getGlobal() {
+    public Optional<ValidatedQuotaDTO> getGlobal() {
         return global;
     }
 
-    public Optional<QuotaDTO> getDomain() {
+    public Optional<ValidatedQuotaDTO> getDomain() {
         return domain;
     }
 
-    public Optional<QuotaDTO> getUser() {
+    public Optional<ValidatedQuotaDTO> getUser() {
         return user;
     }
 
-    public Optional<QuotaDTO> getComputed() {
+    public Optional<ValidatedQuotaDTO> getComputed() {
         return computed;
     }
 
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDomainDTO.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDomainDTO.java
index 527491f..4113418 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDomainDTO.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDomainDTO.java
@@ -29,26 +29,26 @@ public class QuotaDomainDTO {
     }
 
     public static class Builder {
-        private Optional<QuotaDTO> global;
-        private Optional<QuotaDTO> domain;
-        private Optional<QuotaDTO> computed;
+        private Optional<ValidatedQuotaDTO> global;
+        private Optional<ValidatedQuotaDTO> domain;
+        private Optional<ValidatedQuotaDTO> computed;
 
         private Builder() {
             global = Optional.empty();
             computed = Optional.empty();
         }
 
-        public Builder global(QuotaDTO.Builder global) {
+        public Builder global(ValidatedQuotaDTO.Builder global) {
             this.global = Optional.of(global.build());
             return this;
         }
 
-        public Builder domain(QuotaDTO.Builder domain) {
+        public Builder domain(ValidatedQuotaDTO.Builder domain) {
             this.domain = Optional.of(domain.build());
             return this;
         }
 
-        public Builder computed(QuotaDTO.Builder computed) {
+        public Builder computed(ValidatedQuotaDTO.Builder computed) {
             this.computed = Optional.of(computed.build());
             return this;
         }
@@ -58,25 +58,25 @@ public class QuotaDomainDTO {
         }
     }
 
-    private final Optional<QuotaDTO> global;
-    private final Optional<QuotaDTO> domain;
-    private final Optional<QuotaDTO> computed;
+    private final Optional<ValidatedQuotaDTO> global;
+    private final Optional<ValidatedQuotaDTO> domain;
+    private final Optional<ValidatedQuotaDTO> computed;
 
-    private QuotaDomainDTO(Optional<QuotaDTO> global, Optional<QuotaDTO> 
domain, Optional<QuotaDTO> computed) {
+    private QuotaDomainDTO(Optional<ValidatedQuotaDTO> global, 
Optional<ValidatedQuotaDTO> domain, Optional<ValidatedQuotaDTO> computed) {
         this.global = global;
         this.domain = domain;
         this.computed = computed;
     }
 
-    public Optional<QuotaDTO> getGlobal() {
+    public Optional<ValidatedQuotaDTO> getGlobal() {
         return global;
     }
 
-    public Optional<QuotaDTO> getDomain() {
+    public Optional<ValidatedQuotaDTO> getDomain() {
         return domain;
     }
 
-    public Optional<QuotaDTO> getComputed() {
+    public Optional<ValidatedQuotaDTO> getComputed() {
         return computed;
     }
 }
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/ValidatedQuotaDTO.java
similarity index 88%
copy from 
server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
copy to 
server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/ValidatedQuotaDTO.java
index 9a02cc6..6023096 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/QuotaDTO.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/ValidatedQuotaDTO.java
@@ -30,8 +30,8 @@ import 
com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
 import com.google.common.base.MoreObjects;
 
-@JsonDeserialize(builder = QuotaDTO.Builder.class)
-public class QuotaDTO {
+@JsonDeserialize(builder = ValidatedQuotaDTO.Builder.class)
+public class ValidatedQuotaDTO {
 
     public static Builder builder() {
         return new Builder();
@@ -57,15 +57,16 @@ public class QuotaDTO {
             return this;
         }
 
-        public QuotaDTO build() {
-            return new QuotaDTO(count, size);
+        public ValidatedQuotaDTO build() {
+            return new ValidatedQuotaDTO(count, size);
         }
     }
 
+
     private final Optional<QuotaCount> count;
     private final Optional<QuotaSize> size;
 
-    private QuotaDTO(Optional<QuotaCount> count, Optional<QuotaSize> size) {
+    private ValidatedQuotaDTO(Optional<QuotaCount> count, Optional<QuotaSize> 
size) {
         this.count = count;
         this.size = size;
     }
@@ -80,8 +81,8 @@ public class QuotaDTO {
 
     @Override
     public boolean equals(Object o) {
-        if (o instanceof QuotaDTO) {
-            QuotaDTO that = (QuotaDTO) o;
+        if (o instanceof ValidatedQuotaDTO) {
+            ValidatedQuotaDTO that = (ValidatedQuotaDTO) o;
 
             return Objects.equals(this.count, that.count) &&
                 Objects.equals(this.size, that.size);
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaRoutes.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaRoutes.java
index 115bb83..c080910 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaRoutes.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/DomainQuotaRoutes.java
@@ -40,14 +40,15 @@ import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.webadmin.Routes;
 import org.apache.james.webadmin.dto.QuotaDTO;
 import org.apache.james.webadmin.dto.QuotaDomainDTO;
+import org.apache.james.webadmin.dto.ValidatedQuotaDTO;
 import org.apache.james.webadmin.service.DomainQuotaService;
 import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.james.webadmin.utils.ErrorResponder.ErrorType;
-import org.apache.james.webadmin.utils.JsonExtractException;
 import org.apache.james.webadmin.utils.JsonExtractor;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.apache.james.webadmin.utils.JsonTransformerModule;
 import org.apache.james.webadmin.utils.Responses;
+import org.apache.james.webadmin.validation.QuotaDTOValidator;
 import org.apache.james.webadmin.validation.Quotas;
 import org.eclipse.jetty.http.HttpStatus;
 
@@ -76,6 +77,7 @@ public class DomainQuotaRoutes implements Routes {
     private final UsersRepository usersRepository;
     private final JsonTransformer jsonTransformer;
     private final JsonExtractor<QuotaDTO> jsonExtractor;
+    private final QuotaDTOValidator quotaDTOValidator;
     private Service service;
 
     @Inject
@@ -85,6 +87,7 @@ public class DomainQuotaRoutes implements Routes {
         this.usersRepository = usersRepository;
         this.jsonTransformer = jsonTransformer;
         this.jsonExtractor = new JsonExtractor<>(QuotaDTO.class, 
modules.stream().map(JsonTransformerModule::asJacksonModule).collect(Collectors.toList()));
+        this.quotaDTOValidator = new QuotaDTOValidator();
     }
 
     @Override
@@ -130,10 +133,20 @@ public class DomainQuotaRoutes implements Routes {
     })
     public void defineUpdateQuota() {
         service.put(QUOTA_ENDPOINT, ((request, response) -> {
-            Domain domain = checkDomainExist(request);
-            QuotaDTO quotaDTO = parseQuotaDTO(request);
-            domainQuotaService.defineQuota(domain, quotaDTO);
-            return Responses.returnNoContent(response);
+            try {
+                Domain domain = checkDomainExist(request);
+                QuotaDTO quotaDTO = jsonExtractor.parse(request.body());
+                ValidatedQuotaDTO validatedQuotaDTO = 
quotaDTOValidator.validatedQuotaDTO(quotaDTO);
+                domainQuotaService.defineQuota(domain, validatedQuotaDTO);
+                return Responses.returnNoContent(response);
+            } catch (IllegalArgumentException e) {
+                throw ErrorResponder.builder()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .type(ErrorType.INVALID_ARGUMENT)
+                    .message("Quota should be positive or unlimited (-1)")
+                    .cause(e)
+                    .haltError();
+            }
         }));
     }
 
@@ -307,25 +320,4 @@ public class DomainQuotaRoutes implements Routes {
                 .haltError();
         }
     }
-
-    private QuotaDTO parseQuotaDTO(Request request) {
-        try {
-            return jsonExtractor.parse(request.body());
-        } catch (IllegalArgumentException e) {
-            throw ErrorResponder.builder()
-                .statusCode(HttpStatus.BAD_REQUEST_400)
-                .type(ErrorType.INVALID_ARGUMENT)
-                .message("Quota should be positive or unlimited (-1)")
-                .cause(e)
-                .haltError();
-        } catch (JsonExtractException e) {
-            throw ErrorResponder.builder()
-                .statusCode(HttpStatus.BAD_REQUEST_400)
-                .type(ErrorType.INVALID_ARGUMENT)
-                .message("Malformed JSON input")
-                .cause(e)
-                .haltError();
-        }
-    }
-
 }
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
index a1c4cb6..a4c255f 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/GlobalQuotaRoutes.java
@@ -33,14 +33,15 @@ import org.apache.james.core.quota.QuotaSize;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.webadmin.Routes;
 import org.apache.james.webadmin.dto.QuotaDTO;
+import org.apache.james.webadmin.dto.ValidatedQuotaDTO;
 import org.apache.james.webadmin.jackson.QuotaModule;
 import org.apache.james.webadmin.service.GlobalQuotaService;
 import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.james.webadmin.utils.ErrorResponder.ErrorType;
-import org.apache.james.webadmin.utils.JsonExtractException;
 import org.apache.james.webadmin.utils.JsonExtractor;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.apache.james.webadmin.utils.Responses;
+import org.apache.james.webadmin.validation.QuotaDTOValidator;
 import org.apache.james.webadmin.validation.Quotas;
 import org.eclipse.jetty.http.HttpStatus;
 
@@ -65,6 +66,7 @@ public class GlobalQuotaRoutes implements Routes {
 
     private final JsonTransformer jsonTransformer;
     private final JsonExtractor<QuotaDTO> jsonExtractor;
+    private final QuotaDTOValidator quotaDTOValidator;
     private final GlobalQuotaService globalQuotaService;
     private Service service;
 
@@ -73,6 +75,7 @@ public class GlobalQuotaRoutes implements Routes {
         this.globalQuotaService = globalQuotaService;
         this.jsonTransformer = jsonTransformer;
         this.jsonExtractor = new JsonExtractor<>(QuotaDTO.class, new 
QuotaModule().asJacksonModule());
+        quotaDTOValidator = new QuotaDTOValidator();
     }
 
     @Override
@@ -115,15 +118,9 @@ public class GlobalQuotaRoutes implements Routes {
         service.put(QUOTA_ENDPOINT, ((request, response) -> {
             try {
                 QuotaDTO quotaDTO = jsonExtractor.parse(request.body());
-                globalQuotaService.defineQuota(quotaDTO);
+                ValidatedQuotaDTO validatedQuotaDTO = 
quotaDTOValidator.validatedQuotaDTO(quotaDTO);
+                globalQuotaService.defineQuota(validatedQuotaDTO);
                 return Responses.returnNoContent(response);
-            } catch (JsonExtractException e) {
-                throw ErrorResponder.builder()
-                    .statusCode(HttpStatus.BAD_REQUEST_400)
-                    .type(ErrorType.INVALID_ARGUMENT)
-                    .message("Malformed JSON input")
-                    .cause(e)
-                    .haltError();
             } catch (IllegalArgumentException e) {
                 throw ErrorResponder.builder()
                     .statusCode(HttpStatus.BAD_REQUEST_400)
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
index e06818c..4fbf4cc 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
@@ -46,6 +46,7 @@ import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.webadmin.Routes;
 import org.apache.james.webadmin.dto.QuotaDTO;
 import org.apache.james.webadmin.dto.QuotaDetailsDTO;
+import org.apache.james.webadmin.dto.ValidatedQuotaDTO;
 import org.apache.james.webadmin.service.UserQuotaService;
 import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.james.webadmin.utils.ErrorResponder.ErrorType;
@@ -55,6 +56,7 @@ import org.apache.james.webadmin.utils.JsonTransformer;
 import org.apache.james.webadmin.utils.JsonTransformerModule;
 import org.apache.james.webadmin.utils.ParametersExtractor;
 import org.apache.james.webadmin.utils.Responses;
+import org.apache.james.webadmin.validation.QuotaDTOValidator;
 import org.apache.james.webadmin.validation.Quotas;
 import org.eclipse.jetty.http.HttpStatus;
 
@@ -85,6 +87,7 @@ public class UserQuotaRoutes implements Routes {
     private final UserQuotaService userQuotaService;
     private final JsonTransformer jsonTransformer;
     private final JsonExtractor<QuotaDTO> jsonExtractor;
+    private final QuotaDTOValidator quotaDTOValidator;
     private Service service;
 
     @Inject
@@ -93,6 +96,7 @@ public class UserQuotaRoutes implements Routes {
         this.userQuotaService = userQuotaService;
         this.jsonTransformer = jsonTransformer;
         this.jsonExtractor = new JsonExtractor<>(QuotaDTO.class, 
modules.stream().map(JsonTransformerModule::asJacksonModule).collect(Collectors.toList()));
+        this.quotaDTOValidator = new QuotaDTOValidator();
     }
 
     @Override
@@ -131,10 +135,20 @@ public class UserQuotaRoutes implements Routes {
     })
     public void defineUpdateQuota() {
         service.put(QUOTA_ENDPOINT, ((request, response) -> {
-            Username username = checkUserExist(request);
-            QuotaDTO quotaDTO = parseQuotaDTO(request);
-            userQuotaService.defineQuota(username, quotaDTO);
-            return Responses.returnNoContent(response);
+            try {
+                Username username = checkUserExist(request);
+                QuotaDTO quotaDTO = jsonExtractor.parse(request.body());
+                ValidatedQuotaDTO validatedQuotaDTO = 
quotaDTOValidator.validatedQuotaDTO(quotaDTO);
+                userQuotaService.defineQuota(username, validatedQuotaDTO);
+                return Responses.returnNoContent(response);
+            } catch (IllegalArgumentException e) {
+                throw ErrorResponder.builder()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .type(ErrorType.INVALID_ARGUMENT)
+                    .message("Quota should be positive or unlimited (-1)")
+                    .cause(e)
+                    .haltError();
+            }
         }));
     }
 
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/DomainQuotaService.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/DomainQuotaService.java
index 0c30c19..e9b7491 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/DomainQuotaService.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/DomainQuotaService.java
@@ -28,8 +28,8 @@ import org.apache.james.core.quota.QuotaCount;
 import org.apache.james.core.quota.QuotaSize;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.quota.MaxQuotaManager;
-import org.apache.james.webadmin.dto.QuotaDTO;
 import org.apache.james.webadmin.dto.QuotaDomainDTO;
+import org.apache.james.webadmin.dto.ValidatedQuotaDTO;
 
 public class DomainQuotaService {
 
@@ -66,22 +66,22 @@ public class DomainQuotaService {
 
     public QuotaDomainDTO getQuota(Domain domain) throws MailboxException {
         return QuotaDomainDTO.builder()
-            .domain(QuotaDTO
+            .domain(ValidatedQuotaDTO
                 .builder()
                 .count(maxQuotaManager.getDomainMaxMessage(domain))
                 .size(maxQuotaManager.getDomainMaxStorage(domain)))
-            .global(QuotaDTO
+            .global(ValidatedQuotaDTO
                 .builder()
                 .count(maxQuotaManager.getGlobalMaxMessage())
                 .size(maxQuotaManager.getGlobalMaxStorage()))
-            .computed(QuotaDTO
+            .computed(ValidatedQuotaDTO
                 .builder()
                 .count(maxQuotaManager.getComputedMaxMessage(domain))
                 .size(maxQuotaManager.getComputedMaxStorage(domain)))
             .build();
     }
 
-    public void defineQuota(Domain domain, QuotaDTO quota) {
+    public void defineQuota(Domain domain, ValidatedQuotaDTO quota) {
         try {
             if (quota.getCount().isPresent()) {
                 maxQuotaManager.setDomainMaxMessage(domain, 
quota.getCount().get());
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/GlobalQuotaService.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/GlobalQuotaService.java
index 83e7a32..abd3aed 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/GlobalQuotaService.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/GlobalQuotaService.java
@@ -26,7 +26,7 @@ import org.apache.james.core.quota.QuotaCount;
 import org.apache.james.core.quota.QuotaSize;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.quota.MaxQuotaManager;
-import org.apache.james.webadmin.dto.QuotaDTO;
+import org.apache.james.webadmin.dto.ValidatedQuotaDTO;
 
 public class GlobalQuotaService {
 
@@ -37,7 +37,7 @@ public class GlobalQuotaService {
         this.maxQuotaManager = maxQuotaManager;
     }
 
-    public void defineQuota(QuotaDTO quota) throws MailboxException {
+    public void defineQuota(ValidatedQuotaDTO quota) throws MailboxException {
         Optional<QuotaCount> count = quota.getCount();
         if (count.isPresent()) {
             maxQuotaManager.setGlobalMaxMessage(count.get());
@@ -53,8 +53,8 @@ public class GlobalQuotaService {
         }
     }
 
-    public QuotaDTO getQuota() throws MailboxException {
-        return QuotaDTO
+    public ValidatedQuotaDTO getQuota() throws MailboxException {
+        return ValidatedQuotaDTO
             .builder()
             .count(maxQuotaManager.getGlobalMaxMessage())
             .size(maxQuotaManager.getGlobalMaxStorage())
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java
index 0edddc8..1aaf012 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java
@@ -37,9 +37,9 @@ import org.apache.james.mailbox.quota.QuotaManager;
 import org.apache.james.mailbox.quota.UserQuotaRootResolver;
 import org.apache.james.quota.search.QuotaQuery;
 import org.apache.james.quota.search.QuotaSearcher;
-import org.apache.james.webadmin.dto.QuotaDTO;
 import org.apache.james.webadmin.dto.QuotaDetailsDTO;
 import org.apache.james.webadmin.dto.UsersQuotaDetailsDTO;
+import org.apache.james.webadmin.dto.ValidatedQuotaDTO;
 
 import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
@@ -60,7 +60,7 @@ public class UserQuotaService {
         this.quotaSearcher = quotaSearcher;
     }
 
-    public void defineQuota(Username username, QuotaDTO quota) {
+    public void defineQuota(Username username, ValidatedQuotaDTO quota) {
         try {
             QuotaRoot quotaRoot = userQuotaRootResolver.forUser(username);
             if (quota.getCount().isPresent()) {
@@ -94,19 +94,19 @@ public class UserQuotaService {
         return quotaDetails.build();
     }
 
-    private QuotaDTO computedQuota(QuotaRoot quotaRoot) throws 
MailboxException {
-        return QuotaDTO
+    private ValidatedQuotaDTO computedQuota(QuotaRoot quotaRoot) throws 
MailboxException {
+        return ValidatedQuotaDTO
                 .builder()
                 .count(maxQuotaManager.getMaxMessage(quotaRoot))
                 .size(maxQuotaManager.getMaxStorage(quotaRoot))
                 .build();
     }
 
-    private Map<Quota.Scope, QuotaDTO> mergeMaps(Map<Quota.Scope, QuotaCount> 
counts, Map<Quota.Scope, QuotaSize> sizes) {
+    private Map<Quota.Scope, ValidatedQuotaDTO> mergeMaps(Map<Quota.Scope, 
QuotaCount> counts, Map<Quota.Scope, QuotaSize> sizes) {
        return Sets.union(counts.keySet(), sizes.keySet())
             .stream()
             .collect(Collectors.toMap(Function.identity(),
-                scope -> QuotaDTO
+                scope -> ValidatedQuotaDTO
                             .builder()
                             .count(Optional.ofNullable(counts.get(scope)))
                             .size(Optional.ofNullable(sizes.get(scope)))
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/QuotaDTOValidator.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/QuotaDTOValidator.java
new file mode 100644
index 0000000..63de521
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/validation/QuotaDTOValidator.java
@@ -0,0 +1,70 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.webadmin.validation;
+
+import java.util.Optional;
+
+import org.apache.james.core.quota.QuotaCount;
+import org.apache.james.core.quota.QuotaSize;
+import org.apache.james.webadmin.dto.QuotaDTO;
+import org.apache.james.webadmin.dto.ValidatedQuotaDTO;
+import org.apache.james.webadmin.utils.ErrorResponder;
+import org.eclipse.jetty.http.HttpStatus;
+
+public class QuotaDTOValidator {
+
+    private static final int UNLIMITED = -1;
+
+    public ValidatedQuotaDTO validatedQuotaDTO(QuotaDTO quotaDTO) {
+        try {
+            Optional<QuotaCount> count = quotaDTO.getCount()
+                .map(this::getQuotaCount);
+            Optional<QuotaSize> size = quotaDTO.getSize()
+                .map(this::getQuotaSize);
+
+            return ValidatedQuotaDTO.builder()
+                .count(count)
+                .size(size)
+                .build();
+        } catch (IllegalArgumentException e) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .message("Invalid quota. Need to be an integer value greater 
or equal to -1")
+                .cause(e)
+                .haltError();
+        }
+    }
+
+    private QuotaSize getQuotaSize(Long quotaValue) {
+        if (quotaValue == UNLIMITED) {
+            return QuotaSize.unlimited();
+        } else {
+            return QuotaSize.size(quotaValue);
+        }
+    }
+
+    private QuotaCount getQuotaCount(Long quotaValue) {
+        if (quotaValue == UNLIMITED) {
+            return QuotaCount.unlimited();
+        } else {
+            return QuotaCount.count(quotaValue);
+        }
+    }
+}
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaValueDeserializerTest.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaValueDeserializerTest.java
index 8cb7f28..fd0d679 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaValueDeserializerTest.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/QuotaValueDeserializerTest.java
@@ -32,14 +32,14 @@ class QuotaValueDeserializerTest {
     @Test
     void objectDeserializeShouldContainGivenValues() throws 
JsonExtractException {
         String payload = "{\"count\":52,\"size\":42}";
-        QuotaDTO actual = new JsonExtractor<>(QuotaDTO.class,
+        ValidatedQuotaDTO actual = new JsonExtractor<>(ValidatedQuotaDTO.class,
             new SimpleModule()
                 .addDeserializer(QuotaCount.class, new 
QuotaValueDeserializer<>(QuotaCount.unlimited(), QuotaCount::count))
                 .addDeserializer(QuotaSize.class, new 
QuotaValueDeserializer<>(QuotaSize.unlimited(), QuotaSize::size))
         ).parse(payload);
         Assertions.assertThat(actual)
             .isEqualTo(
-                QuotaDTO
+                ValidatedQuotaDTO
                     .builder()
                     .count(java.util.Optional.of(QuotaCount.count(52)))
                     .size(java.util.Optional.of(QuotaSize.size(42)))
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
index 17c1770..df823e3 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
@@ -29,6 +29,7 @@ import java.util.Map;
 import org.apache.james.core.Domain;
 import org.apache.james.core.quota.QuotaCount;
 import org.apache.james.core.quota.QuotaSize;
+import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.quota.MaxQuotaManager;
 import org.eclipse.jetty.http.HttpStatus;
 import org.junit.jupiter.api.BeforeEach;
@@ -448,6 +449,78 @@ class DomainQuotaRoutesTest {
     }
 
     @Test
+    void putQuotaWithNegativeCountShouldFail() throws MailboxException {
+        maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(52));
+        maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(42));
+        Map<String, Object> errors = given()
+            .body("{\"count\":-5,\"size\":30}")
+            .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM.name())
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .contentType(ContentType.JSON)
+        .extract()
+            .body()
+            .jsonPath()
+            .getMap(".");
+
+        assertThat(errors)
+            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+            .containsEntry("type", "InvalidArgument")
+            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater or equal to -1");
+    }
+
+    @Test
+    void putQuotaWithNegativeCountShouldNotUpdatePreviousQuota() throws 
MailboxException {
+        maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(52));
+        maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(42));
+        given()
+            .body("{\"count\":-5,\"size\":30}")
+            .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM.name())
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .contentType(ContentType.JSON);
+
+        
assertThat(maxQuotaManager.getDomainMaxMessage(TROUVÉ_COM)).contains(QuotaCount.count(52));
+        
assertThat(maxQuotaManager.getDomainMaxStorage(TROUVÉ_COM)).contains(QuotaSize.size(42));
+    }
+
+    @Test
+    void putQuotaWithNegativeSizeShouldFail() throws MailboxException {
+        maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(52));
+        maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(42));
+        Map<String, Object> errors = given()
+            .body("{\"count\":40,\"size\":-19}")
+            .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM.name())
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .contentType(ContentType.JSON)
+        .extract()
+            .body()
+            .jsonPath()
+            .getMap(".");
+
+        assertThat(errors)
+            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+            .containsEntry("type", "InvalidArgument")
+            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater or equal to -1");
+    }
+
+    @Test
+    void putQuotaWithNegativeSizeShouldNotUpdatePreviousQuota() throws 
MailboxException {
+        maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(52));
+        maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(42));
+        given()
+            .body("{\"count\":40,\"size\":-19}")
+            .put(QUOTA_DOMAINS + "/" + TROUVÉ_COM.name())
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .contentType(ContentType.JSON);
+
+        
assertThat(maxQuotaManager.getDomainMaxMessage(TROUVÉ_COM)).contains(QuotaCount.count(52));
+        
assertThat(maxQuotaManager.getDomainMaxStorage(TROUVÉ_COM)).contains(QuotaSize.size(42));
+    }
+
+    @Test
     void putQuotaShouldBeAbleToRemoveBothQuota() {
         given()
             .body("{\"count\":52,\"size\":42}")
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
index 48032b0..2132646 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
@@ -371,6 +371,86 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
+    void putQuotaWithNegativeCountShouldFail() throws Exception {
+        maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
+        maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(43));
+
+        Map<String, Object> errors = given()
+            .body("{\"count\":-2,\"size\":43}")
+            .when()
+            .put("/quota")
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .contentType(ContentType.JSON)
+        .extract()
+            .body()
+            .jsonPath()
+            .getMap(".");
+
+        assertThat(errors)
+            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+            .containsEntry("type", "InvalidArgument")
+            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater or equal to -1");
+    }
+
+    @Test
+    void putQuotaWithNegativeCountShouldNotUpdatePreviousQuota() throws 
Exception {
+        maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
+        maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(43));
+
+        given()
+            .body("{\"count\":-2,\"size\":43}")
+            .when()
+            .put("/quota")
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .contentType(ContentType.JSON);
+
+        
assertThat(maxQuotaManager.getGlobalMaxMessage()).contains(QuotaCount.count(42));
+        
assertThat(maxQuotaManager.getGlobalMaxStorage()).contains(QuotaSize.size(43));
+    }
+
+    @Test
+    void putQuotaWithNegativeSizeShouldFail() throws Exception {
+        maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
+        maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(43));
+
+        Map<String, Object> errors = given()
+            .body("{\"count\":42,\"size\":-2}")
+            .when()
+            .put("/quota")
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .contentType(ContentType.JSON)
+        .extract()
+            .body()
+            .jsonPath()
+            .getMap(".");
+
+        assertThat(errors)
+            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+            .containsEntry("type", "InvalidArgument")
+            .containsEntry("message", "Invalid quota. Need to be an integer 
value greater or equal to -1");
+    }
+
+    @Test
+    void putQuotaWithNegativeSizeShouldNotUpdatePreviousQuota() throws 
Exception {
+        maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
+        maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(43));
+
+        given()
+            .body("{\"count\":42,\"size\":-2}")
+            .when()
+            .put("/quota")
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .contentType(ContentType.JSON);
+
+        
assertThat(maxQuotaManager.getGlobalMaxMessage()).contains(QuotaCount.count(42));
+        
assertThat(maxQuotaManager.getGlobalMaxStorage()).contains(QuotaSize.size(43));
+    }
+
+    @Test
     void putQuotaShouldUnsetCountWhenNull() throws Exception {
         maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
         given()
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
index 1cfe929..8841e27 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
@@ -57,7 +57,6 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 
 import com.google.common.base.Strings;
-
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
 import io.restassured.path.json.JsonPath;
@@ -1055,6 +1054,102 @@ class UserQuotaRoutesTest {
         }
 
         @Test
+        void putQuotaWithNegativeCountShouldFail(WebAdminQuotaSearchTestSystem 
testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = 
testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = 
testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), 
QuotaCount.count(52));
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), 
QuotaSize.size(42));
+
+            Map<String, Object> errors = with()
+                .body("{\"count\":-2,\"size\":42}")
+                .put(QUOTA_USERS + "/" + BOB.asString())
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+            .extract()
+                .body()
+                .jsonPath()
+                .getMap(".");
+
+            assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an 
integer value greater or equal to -1");
+        }
+
+        @Test
+        void 
putQuotaWithNegativeCountShouldNotUpdatePreviousQuota(WebAdminQuotaSearchTestSystem
 testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = 
testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = 
testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), 
QuotaCount.count(52));
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), 
QuotaSize.size(42));
+
+            with()
+                .body("{\"count\":-2,\"size\":42}")
+                .put(QUOTA_USERS + "/" + BOB.asString())
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON);
+
+            SoftAssertions softly = new SoftAssertions();
+            
softly.assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
+                .contains(QuotaCount.count(52));
+            
softly.assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
+                .contains(QuotaSize.size(42));
+            softly.assertAll();
+        }
+
+        @Test
+        void putQuotaWithNegativeSizeShouldFail(WebAdminQuotaSearchTestSystem 
testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = 
testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = 
testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), 
QuotaCount.count(52));
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), 
QuotaSize.size(42));
+
+            Map<String, Object> errors = with()
+                .body("{\"count\":52,\"size\":-3}")
+                .put(QUOTA_USERS + "/" + BOB.asString())
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+            .extract()
+                .body()
+                .jsonPath()
+                .getMap(".");
+
+            assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an 
integer value greater or equal to -1");
+        }
+
+        @Test
+        void 
putQuotaWithNegativeSizeShouldNotUpdatePreviousQuota(WebAdminQuotaSearchTestSystem
 testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = 
testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = 
testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), 
QuotaCount.count(52));
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), 
QuotaSize.size(42));
+
+            with()
+                .body("{\"count\":52,\"size\":-3}")
+                .put(QUOTA_USERS + "/" + BOB.asString())
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON);
+
+            SoftAssertions softly = new SoftAssertions();
+            
softly.assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
+                .contains(QuotaCount.count(52));
+            
softly.assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
+                .contains(QuotaSize.size(42));
+            softly.assertAll();
+        }
+
+        @Test
         void putQuotaShouldUpdateBothQuota(WebAdminQuotaSearchTestSystem 
testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = 
testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = 
testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to