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 @@ + + + + Control Service: Error + + + {{> control/partials/head-includes }} + + +{{> control/partials/nav}} +
+

Error: {{title}}

+
+

{{messageLong}}

+ Go back +
+
+ +{{> control/partials/foot-includes }} + + diff --git a/code/services-core/control-service/src/main/resources/templates/control/sys/domain-ranking-sets.hdb b/code/services-core/control-service/src/main/resources/templates/control/sys/domain-ranking-sets.hdb index 79fcfb32..ba395319 100644 --- a/code/services-core/control-service/src/main/resources/templates/control/sys/domain-ranking-sets.hdb +++ b/code/services-core/control-service/src/main/resources/templates/control/sys/domain-ranking-sets.hdb @@ -32,6 +32,21 @@
New Domain Ranking Set
+ + +
+

Several reserved ranking sets are available for use in the query parameters.

+
+
NONE
Placeholder for no restriction on the domains returned. + Does nothing, and exists only to prevent a new ranking + set from being created with this name.
+
RANK
Used to calculate the domain ranking for a given domain. + This affects the order they are stored in the index, and increases the odds they'll + even be considered within the time restrictions of the query.
+
BLOGS
Returns a fixed list of domains, configurable in Datasets. + Changes to this list will not be reflected in the index until the next time the index is rebuilt.
+
+
{{> control/partials/foot-includes }} diff --git a/code/services-core/control-service/src/main/resources/templates/control/sys/new-domain-ranking-set.hdb b/code/services-core/control-service/src/main/resources/templates/control/sys/new-domain-ranking-set.hdb index 7c086276..bd68e0c4 100644 --- a/code/services-core/control-service/src/main/resources/templates/control/sys/new-domain-ranking-set.hdb +++ b/code/services-core/control-service/src/main/resources/templates/control/sys/new-domain-ranking-set.hdb @@ -11,17 +11,18 @@
- + - + - + - + - +
Name - +
- The name is how the ranking set is identified in the query parameters, + Must be all letters. + The name is how the ranking set is identified in the query parameters, and also decides the file name of the persisted ranking set definition. Keep it simple.
Algorithm
Description
@@ -47,15 +48,15 @@
Depth
- Up to this number of domains are ranked, the rest are excluded. + Number. Up to this number of domains are ranked, the rest are excluded.
Definition
diff --git a/code/services-core/control-service/src/main/resources/templates/control/sys/update-domain-ranking-set.hdb b/code/services-core/control-service/src/main/resources/templates/control/sys/update-domain-ranking-set.hdb index 3e228c67..c36b9a5f 100644 --- a/code/services-core/control-service/src/main/resources/templates/control/sys/update-domain-ranking-set.hdb +++ b/code/services-core/control-service/src/main/resources/templates/control/sys/update-domain-ranking-set.hdb @@ -12,7 +12,7 @@ - + - + - + - + - +
Name {{#if special}}{{/if}} @@ -23,7 +23,7 @@
Algorithm {{#if special}}{{/if}}
Description {{#if special}}{{/if}} @@ -54,15 +54,15 @@
Depth
- Up to this number of domains are ranked, the rest are excluded. + Number. Up to this number of domains are ranked, the rest are excluded.
Definition