diff --git a/code/services-core/control-service/src/main/java/nu/marginalia/control/ControlService.java b/code/services-core/control-service/src/main/java/nu/marginalia/control/ControlService.java index c3a4e88f..e4b5d359 100644 --- a/code/services-core/control-service/src/main/java/nu/marginalia/control/ControlService.java +++ b/code/services-core/control-service/src/main/java/nu/marginalia/control/ControlService.java @@ -54,7 +54,8 @@ public class ControlService extends Service { DataSetsService dataSetsService, ControlNodeService controlNodeService, ControlDomainRankingSetsService controlDomainRankingSetsService, - ControlActorService controlActorService + ControlActorService controlActorService, + ControlErrorHandler errorHandler ) throws IOException { super(params); @@ -81,6 +82,8 @@ public class ControlService extends Service { domainComplaintService.register(); randomExplorationService.register(); + errorHandler.register(); + var indexRenderer = rendererFactory.renderer("control/index"); var eventsRenderer = rendererFactory.renderer("control/sys/events"); var serviceByIdRenderer = rendererFactory.renderer("control/sys/service-by-id"); @@ -106,6 +109,7 @@ public class ControlService extends Service { Spark.get("/public/:resource", this::serveStatic); + monitors.subscribe(this::logMonitorStateChange); controlActorService.startDefaultActors(); diff --git a/code/services-core/control-service/src/main/java/nu/marginalia/control/ControlValidationError.java b/code/services-core/control-service/src/main/java/nu/marginalia/control/ControlValidationError.java new file mode 100644 index 00000000..29ff7317 --- /dev/null +++ b/code/services-core/control-service/src/main/java/nu/marginalia/control/ControlValidationError.java @@ -0,0 +1,15 @@ +package nu.marginalia.control; + +public class ControlValidationError extends RuntimeException { + public final String title; + public final String messageLong; + public final String redirect; + + public ControlValidationError(String title, String messageLong, String redirect) { + super(title); + + this.title = title; + this.messageLong = messageLong; + this.redirect = redirect; + } +} diff --git a/code/services-core/control-service/src/main/java/nu/marginalia/control/sys/svc/ControlDomainRankingSetsService.java b/code/services-core/control-service/src/main/java/nu/marginalia/control/sys/svc/ControlDomainRankingSetsService.java index 362ef0f8..73f19611 100644 --- a/code/services-core/control-service/src/main/java/nu/marginalia/control/sys/svc/ControlDomainRankingSetsService.java +++ b/code/services-core/control-service/src/main/java/nu/marginalia/control/sys/svc/ControlDomainRankingSetsService.java @@ -3,6 +3,7 @@ package nu.marginalia.control.sys.svc; import com.google.inject.Inject; import com.zaxxer.hikari.HikariDataSource; import nu.marginalia.control.ControlRendererFactory; +import nu.marginalia.control.ControlValidationError; import nu.marginalia.control.Redirects; import nu.marginalia.db.DomainRankingSetsService; import spark.Request; @@ -41,6 +42,7 @@ public class ControlDomainRankingSetsService { private Object alterSetModel(Request request, Response response) throws SQLException { final String act = request.queryParams("act"); final String id = request.params("id"); + if ("update".equals(act)) { domainRankingSetsService.upsert(new DomainRankingSetsService.DomainRankingSet( id, @@ -54,18 +56,26 @@ public class ControlDomainRankingSetsService { else if ("delete".equals(act)) { var model = domainRankingSetsService.get(id).orElseThrow(); if (model.isSpecial()) { - throw new IllegalArgumentException("Cannot delete special ranking set"); + throw new ControlValidationError("Cannot delete special ranking set", + """ + SPECIAL data sets are reserved by the system and can not be deleted. + """, + "/domain-ranking-sets"); } domainRankingSetsService.delete(model); return ""; } else if ("create".equals(act)) { if (domainRankingSetsService.get(request.queryParams("name")).isPresent()) { - throw new IllegalArgumentException("Ranking set with that name already exists"); + throw new ControlValidationError("Ranking set with that name already exists", + """ + Ensure the new data set has a unique name and try again. + """, + "/domain-ranking-sets"); } domainRankingSetsService.upsert(new DomainRankingSetsService.DomainRankingSet( - request.queryParams("name"), + request.queryParams("name").toUpperCase(), request.queryParams("description"), DomainRankingSetsService.DomainSetAlgorithm.valueOf(request.queryParams("algorithm")), Integer.parseInt(request.queryParams("depth")), @@ -74,7 +84,10 @@ public class ControlDomainRankingSetsService { return ""; } - throw new UnsupportedOperationException(); + throw new ControlValidationError("Unknown action", """ + An unknown action was requested and the system does not understand how to act on it. + """, + "/domain-ranking-sets"); } private Object rankingSetsModel(Request request, Response response) { diff --git a/code/services-core/control-service/src/main/java/nu/marginalia/control/sys/svc/ControlErrorHandler.java b/code/services-core/control-service/src/main/java/nu/marginalia/control/sys/svc/ControlErrorHandler.java new file mode 100644 index 00000000..277d84fc --- /dev/null +++ b/code/services-core/control-service/src/main/java/nu/marginalia/control/sys/svc/ControlErrorHandler.java @@ -0,0 +1,35 @@ +package nu.marginalia.control.sys.svc; + +import com.google.inject.Inject; +import nu.marginalia.control.ControlRendererFactory; +import nu.marginalia.control.ControlValidationError; +import spark.Request; +import spark.Response; +import spark.Spark; + +import java.util.Map; + +public class ControlErrorHandler { + private final ControlRendererFactory.Renderer renderer; + + @Inject + public ControlErrorHandler(ControlRendererFactory rendererFactory) { + this.renderer = rendererFactory.renderer("control/error"); + } + + public void render(ControlValidationError error, Request request, Response response) { + String text = renderer.render( + Map.of( + "title", error.title, + "messageLong", error.messageLong, + "redirect", error.redirect + ) + ); + + response.body(text); + } + + public void register() { + Spark.exception(ControlValidationError.class, this::render); + } +} diff --git a/code/services-core/control-service/src/main/resources/templates/control/error.hdb b/code/services-core/control-service/src/main/resources/templates/control/error.hdb new file mode 100644 index 00000000..d973163d --- /dev/null +++ b/code/services-core/control-service/src/main/resources/templates/control/error.hdb @@ -0,0 +1,25 @@ + + +
+{{messageLong}}
+ Go back +Several reserved ranking sets are available for use in the query parameters.
+