From e9a90ad1b37e84d6c486f007a42dbd2bb3b22f92 Mon Sep 17 00:00:00 2001 From: Max Thonagel <12283268+thoniTUB@users.noreply.github.com> Date: Thu, 18 Aug 2022 15:59:25 +0200 Subject: [PATCH] adds ManualConfig to set manual configs for internal forms or override urls provided by external form frontend configs --- .../conquery/models/config/ManualConfig.java | 90 +++++++++++++++++++ .../frontendconfiguration/FormScanner.java | 59 +++++++----- 2 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 backend/src/main/java/com/bakdata/conquery/models/config/ManualConfig.java diff --git a/backend/src/main/java/com/bakdata/conquery/models/config/ManualConfig.java b/backend/src/main/java/com/bakdata/conquery/models/config/ManualConfig.java new file mode 100644 index 0000000000..a6d73442f6 --- /dev/null +++ b/backend/src/main/java/com/bakdata/conquery/models/config/ManualConfig.java @@ -0,0 +1,90 @@ +package com.bakdata.conquery.models.config; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.net.MalformedURLException; +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; +import javax.validation.Constraint; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.Payload; + +import com.bakdata.conquery.io.cps.CPSType; +import lombok.Getter; +import lombok.Setter; + +@CPSType(id = "MANUAL", base = PluginConfig.class) +@Getter +@Setter +public class ManualConfig implements PluginConfig { + + + private Map forms = Collections.emptyMap(); + + @Target({ANNOTATION_TYPE, FIELD, TYPE_USE}) + @Retention(RUNTIME) + @Constraint(validatedBy = ManualURIValidator.class) + @Documented + public @interface ManualURI { + String message() default ""; + + Class[] groups() default {}; + + @SuppressWarnings("UnusedDeclaration") Class[] payload() default {}; + } + + public static class ManualURIValidator implements ConstraintValidator { + + @Override + public boolean isValid(URI value, ConstraintValidatorContext context) { + + if (value == null) { + return true; + } + + context.disableDefaultConstraintViolation(); + + boolean isValid = true; + + if (value.isOpaque()) { + isValid = false; + context.buildConstraintViolationWithTemplate("The URI was opaque") + .addConstraintViolation(); + } + + if (value.isAbsolute()) { + try { + var unused = value.toURL(); + } + catch (MalformedURLException e) { + isValid = false; + context.buildConstraintViolationWithTemplate("Absolute URI is not a valid URL (" + e.getMessage() + ")") + .addConstraintViolation(); + } + if (!List.of("http", "https").contains(value.getScheme())) { + isValid = false; + context.buildConstraintViolationWithTemplate("The URI has an unsupported Scheme: " + value.getScheme()) + .addConstraintViolation(); + } + } + else { + if (value.getAuthority() != null) { + isValid = false; + context.buildConstraintViolationWithTemplate("The URI is not absolute but has an authority: " + value.getAuthority()) + .addConstraintViolation(); + } + } + + return isValid; + } + } +} diff --git a/backend/src/main/java/com/bakdata/conquery/models/forms/frontendconfiguration/FormScanner.java b/backend/src/main/java/com/bakdata/conquery/models/forms/frontendconfiguration/FormScanner.java index 317152e4b9..a7ae905eea 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/forms/frontendconfiguration/FormScanner.java +++ b/backend/src/main/java/com/bakdata/conquery/models/forms/frontendconfiguration/FormScanner.java @@ -2,6 +2,7 @@ import java.io.PrintWriter; import java.lang.reflect.Modifier; +import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -15,6 +16,7 @@ import com.bakdata.conquery.io.cps.CPSTypeIdResolver; import com.bakdata.conquery.models.config.ConqueryConfig; import com.bakdata.conquery.models.config.FrontendConfig; +import com.bakdata.conquery.models.config.ManualConfig; import com.bakdata.conquery.resources.admin.rest.AdminProcessor; import com.bakdata.conquery.util.QueryUtils; import com.fasterxml.jackson.databind.JsonNode; @@ -118,12 +120,27 @@ private Map generateFEFormConfigMap() { } // Make relative handbook URLs relative to configured handbook base - final JsonNode manualUrl = configTree.get(MANUAL_URL_KEY); + // Config url mappings override urls from frontend config jsons + final URI manualURL = config.getPluginConfig(ManualConfig.class) + // first check override + .map(ManualConfig::getForms) + .map(m -> m.get(fullTypeIdentifier)) + // then query the frontend config json + .orElseGet(() -> { + final JsonNode manualUrl = configTree.get(MANUAL_URL_KEY); + if (!manualUrl.isTextual()) { + log.warn("FrontendFormConfig {} contained field 'manualUrl' but it was not a text. Was: '{}'.", fullTypeIdentifier, manualUrl.getNodeType()); + return null; + } + + return URI.create(manualUrl.textValue()); + }); final URL manualBaseUrl = config.getFrontend().getManualUrl(); - if (manualBaseUrl != null && manualUrl != null) { - final TextNode manualNode = relativizeManualUrl(fullTypeIdentifier, manualUrl, manualBaseUrl); + if (manualBaseUrl != null && manualURL != null) { + + final TextNode manualNode = relativizeManualUrl(fullTypeIdentifier, manualURL, manualBaseUrl); if (manualNode == null) { - log.warn("Manual url relativiation did not succeed for {}. Skipping registration.", fullTypeIdentifier); + log.warn("Manual url relativization did not succeed for {}. Skipping registration.", fullTypeIdentifier); continue; } configTree.set(MANUAL_URL_KEY, manualNode); @@ -137,26 +154,26 @@ private Map generateFEFormConfigMap() { return result.build(); } - private TextNode relativizeManualUrl(@NonNull String formTypeIdentifier, @NonNull JsonNode manualUrl, @NonNull URL manualBaseUrl) { - if (!manualUrl.isTextual()) { - log.warn("FrontendFormConfig {} contained field 'manualUrl' but it was not a text. Was: '{}'.", formTypeIdentifier, manualUrl.getNodeType()); - return null; - } - - final String urlString = manualUrl.textValue(); - final URI manualUri = URI.create(urlString); - if (manualUri.isAbsolute()) { - log.trace("Manual url for {} was already absolute: {}. Skipping relativization.", formTypeIdentifier, manualUri); - return new TextNode(urlString); - } + private TextNode relativizeManualUrl(@NonNull String formTypeIdentifier, @NonNull URI manualUri, @NonNull URL manualBaseUrl) { try { - final String absoluteUrl = manualBaseUrl.toURI().resolve(manualUri).toString(); - log.trace("Computed manual url for {}: {}", formTypeIdentifier, absoluteUrl); - return new TextNode(absoluteUrl); + if (manualUri.isAbsolute()) { + log.trace("Manual url for {} was already absolute: {}. Skipping relativization.", formTypeIdentifier, manualUri); + return new TextNode(manualUri.toURL().toString()); + } + + try { + final String absoluteUrl = manualBaseUrl.toURI().resolve(manualUri).toURL().toString(); + log.trace("Computed manual url for {}: {}", formTypeIdentifier, absoluteUrl); + return new TextNode(absoluteUrl); + } + catch (URISyntaxException e) { + log.warn("Unable to resolve manual base url ('{}') and relative manual url ('{}')", manualBaseUrl, manualUri, e); + return null; + } } - catch (URISyntaxException e) { - log.warn("Unable to resolve manual base url ('{}') and relative manual url ('{}')", manualBaseUrl, manualUri, e); + catch (MalformedURLException e) { + log.error("Unable to build url", e); return null; } }