diff --git a/pom.xml b/pom.xml
index c670a1ed..e8552c9a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -346,6 +346,11 @@
commons-text
1.8
+
+ com.github.vladimir-bukhtoyarov
+ bucket4j-core
+ 4.10.0
+
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/TooManyRegistrations.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/TooManyRegistrations.java
new file mode 100644
index 00000000..55cacedd
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/TooManyRegistrations.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gbl.api;
+
+public class TooManyRegistrations {
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/TooManyRequests.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/TooManyRequests.java
new file mode 100644
index 00000000..bf29ba48
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/TooManyRequests.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gbl.api;
+
+public class TooManyRequests extends RuntimeException {
+
+ private static final long serialVersionUID = 3303246002774619224L;
+
+ public static enum Code {
+ INCOMMING,
+ REGISTRATION
+ }
+
+ public final Code code;
+
+ public TooManyRequests() {
+ super("TooManyRequests");
+ this.code = Code.INCOMMING;
+ }
+
+ public TooManyRequests(final Code code) {
+ super("TooManyRequests");
+ this.code = code;
+ }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/RegisterPage.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/RegisterPage.java
index c034f6c7..00433b02 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/content/RegisterPage.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/RegisterPage.java
@@ -232,7 +232,7 @@ public class RegisterPage implements TemplateComposer {
registerButton.addListener(SWT.Selection, event -> {
registerForm.getForm().clearErrors();
- final Result onError = this.pageService
+ final Result result = this.pageService
.getRestService()
.getBuilder(RegisterNewUser.class)
.withRestTemplate(this.restTemplate)
@@ -240,7 +240,7 @@ public class RegisterPage implements TemplateComposer {
.call()
.onError(registerForm::handleError);
- if (onError.hasError()) {
+ if (result.hasError()) {
return;
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java
index 80e2f73c..54b3b365 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/FormHandle.java
@@ -14,10 +14,13 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
+import ch.ethz.seb.sebserver.gbl.api.TooManyRequests;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
@@ -35,7 +38,11 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
public class FormHandle {
+ private static final Logger log = LoggerFactory.getLogger(FormHandle.class);
+
public static final String FIELD_VALIDATION_LOCTEXT_PREFIX = "sebserver.form.validation.fieldError.";
+ static final LocTextKey MESSAGE_TOO_MANY_REQUESTS_TEXT =
+ new LocTextKey("sebserver.error.tooManyRequests");
private final PageService pageService;
private final PageContext pageContext;
@@ -169,12 +176,27 @@ public class FormHandle {
}
private void handleUnexpectedError(final Exception error) {
- if (this.post != null && this.post.getEntityType() != null) {
- this.pageContext.notifySaveError(this.post.getEntityType(), error);
- } else {
- this.pageContext.notifyError(
- new LocTextKey(PageContext.GENERIC_SAVE_ERROR_TEXT_KEY, StringUtils.EMPTY),
- error);
+ try {
+ if (error instanceof TooManyRequests) {
+ final TooManyRequests.Code code = ((TooManyRequests) error).code;
+ if (code != null) {
+ this.pageContext.publishInfo(new LocTextKey(MESSAGE_TOO_MANY_REQUESTS_TEXT.name + "." + code));
+ } else {
+ this.pageContext.publishInfo(MESSAGE_TOO_MANY_REQUESTS_TEXT);
+ }
+
+ return;
+ }
+
+ if (this.post != null && this.post.getEntityType() != null) {
+ this.pageContext.notifySaveError(this.post.getEntityType(), error);
+ } else {
+ this.pageContext.notifyError(
+ new LocTextKey(PageContext.GENERIC_SAVE_ERROR_TEXT_KEY, StringUtils.EMPTY),
+ error);
+ }
+ } catch (final Exception e) {
+ log.error("Failed to handle unexpected error: ", e);
}
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java
index 95785864..3fc41d7e 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java
@@ -40,6 +40,7 @@ import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
+import ch.ethz.seb.sebserver.gbl.api.TooManyRequests;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.PageSortOrder;
@@ -134,6 +135,15 @@ public abstract class RestCall {
}
} catch (final RestClientResponseException responseError) {
+ if (responseError.getRawStatusCode() == HttpStatus.TOO_MANY_REQUESTS.value()) {
+ final String code = responseError.getResponseBodyAsString();
+ if (StringUtils.isNotBlank(code)) {
+ return Result.ofError(new TooManyRequests(TooManyRequests.Code.valueOf(code)));
+ } else {
+ return Result.ofError(new TooManyRequests());
+ }
+ }
+
final RestCallError restCallError = new RestCallError("Unexpected error while rest call", responseError);
try {
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/APIExceptionHandler.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/APIExceptionHandler.java
index 4667dbef..5bf6892e 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/APIExceptionHandler.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/APIExceptionHandler.java
@@ -33,6 +33,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
+import ch.ethz.seb.sebserver.gbl.api.TooManyRequests;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PermissionDeniedException;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException;
@@ -87,6 +88,15 @@ public class APIExceptionHandler extends ResponseEntityExceptionHandler {
HttpStatus.BAD_REQUEST);
}
+ @ExceptionHandler(TooManyRequests.class)
+ public ResponseEntity