diff --git a/src/main/java/run/halo/app/config/ExtensionConfiguration.java b/src/main/java/run/halo/app/config/ExtensionConfiguration.java index 563d3b606..3cd837b45 100644 --- a/src/main/java/run/halo/app/config/ExtensionConfiguration.java +++ b/src/main/java/run/halo/app/config/ExtensionConfiguration.java @@ -46,6 +46,7 @@ import run.halo.app.extension.controller.Controller; import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.ControllerManager; import run.halo.app.extension.router.ExtensionCompositeRouterFunction; +import run.halo.app.infra.ExternalUrlSupplier; import run.halo.app.infra.properties.HaloProperties; import run.halo.app.plugin.HaloPluginManager; import run.halo.app.plugin.resources.JsBundleRuleProvider; @@ -173,9 +174,10 @@ public class ExtensionConfiguration { } @Bean - Controller attachmentController(ExtensionClient client, PluginManager pluginManager) { + Controller attachmentController(ExtensionClient client, PluginManager pluginManager, + ExternalUrlSupplier externalUrl) { return new ControllerBuilder("attachment-controller", client) - .reconciler(new AttachmentReconciler(client, pluginManager)) + .reconciler(new AttachmentReconciler(client, pluginManager, externalUrl)) .extension(new Attachment()) .build(); } diff --git a/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpoint.java b/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpoint.java index cce1effcc..433b8f257 100644 --- a/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpoint.java +++ b/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpoint.java @@ -5,14 +5,12 @@ import static org.springdoc.core.fn.builders.content.Builder.contentBuilder; import static org.springdoc.core.fn.builders.schema.Builder.schemaBuilder; import static org.springframework.web.reactive.function.BodyExtractors.toMultipartData; import static org.springframework.web.reactive.function.server.RequestPredicates.contentType; -import static run.halo.app.core.extension.attachment.Constant.FINALIZER_NAME; import static run.halo.app.extension.ListResult.generateGenericClass; import static run.halo.app.extension.router.QueryParamBuildUtil.buildParametersFromType; import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate; import io.swagger.v3.oas.annotations.media.Schema; import java.util.Optional; -import java.util.Set; import java.util.function.Predicate; import lombok.extern.slf4j.Slf4j; import org.pf4j.PluginManager; @@ -125,8 +123,6 @@ public class AttachmentEndpoint implements CustomEndpoint { // validate the group name spec.setGroupRef(Ref.of(groupName)); } - // set finalizers mandatory - attachment.getMetadata().setFinalizers(Set.of(FINALIZER_NAME)); })) .next() .switchIfEmpty(Mono.error( diff --git a/src/main/java/run/halo/app/core/extension/reconciler/attachment/AttachmentReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/attachment/AttachmentReconciler.java index 4de021b3b..3d7d9a609 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/attachment/AttachmentReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/attachment/AttachmentReconciler.java @@ -1,9 +1,9 @@ package run.halo.app.core.extension.reconciler.attachment; -import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.pf4j.PluginManager; -import org.springframework.web.util.UriUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import run.halo.app.core.extension.attachment.Attachment; @@ -16,6 +16,7 @@ import run.halo.app.extension.ConfigMap; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler.Request; +import run.halo.app.infra.ExternalUrlSupplier; import run.halo.app.infra.exception.NotFoundException; @Slf4j @@ -25,9 +26,13 @@ public class AttachmentReconciler implements Reconciler { private final PluginManager pluginManager; - public AttachmentReconciler(ExtensionClient client, PluginManager pluginManager) { + private final ExternalUrlSupplier externalUrl; + + public AttachmentReconciler(ExtensionClient client, PluginManager pluginManager, + ExternalUrlSupplier externalUrl) { this.client = client; this.pluginManager = pluginManager; + this.externalUrl = externalUrl; } @Override @@ -43,22 +48,25 @@ public class AttachmentReconciler implements Reconciler { .orElseThrow(); var deleteOption = new DeleteOption(attachment, policy, configMap); Flux.fromIterable(pluginManager.getExtensions(AttachmentHandler.class)) - .concatMap(handler -> handler.delete(deleteOption)) - .next() - .switchIfEmpty(Mono.error(() -> new NotFoundException( - "No suitable handler found to delete the attachment"))) - .doOnNext(deleted -> removeFinalizer(deleted.getMetadata().getName())) - .block(); + .concatMap(handler -> handler.delete(deleteOption)).next().switchIfEmpty( + Mono.error(() -> new NotFoundException( + "No suitable handler found to delete the attachment"))) + .doOnNext(deleted -> removeFinalizer(deleted.getMetadata().getName())).block(); return; } + // add finalizer + addFinalizerIfNotSet(request.name(), attachment.getMetadata().getFinalizers()); + var annotations = attachment.getMetadata().getAnnotations(); if (annotations != null) { String permalink = null; var localRelativePath = annotations.get(Constant.LOCAL_REL_PATH_ANNO_KEY); if (localRelativePath != null) { // TODO Add router function here. - permalink = "http://localhost:8090/upload/" + localRelativePath; - permalink = UriUtils.encodePath(permalink, StandardCharsets.UTF_8); + permalink = externalUrl.get() + .resolve("/upload/" + localRelativePath) + .normalize() + .toASCIIString(); } else { var externalLink = annotations.get(Constant.EXTERNAL_LINK_ANNO_KEY); if (externalLink != null) { @@ -85,14 +93,29 @@ public class AttachmentReconciler implements Reconciler { } void removeFinalizer(String attachmentName) { - client.fetch(Attachment.class, attachmentName) - .ifPresent(attachment -> { - var finalizers = attachment.getMetadata().getFinalizers(); - if (finalizers != null && finalizers.remove(Constant.FINALIZER_NAME)) { - // update it - client.update(attachment); - } - }); + client.fetch(Attachment.class, attachmentName).ifPresent(attachment -> { + var finalizers = attachment.getMetadata().getFinalizers(); + if (finalizers != null && finalizers.remove(Constant.FINALIZER_NAME)) { + // update it + client.update(attachment); + } + }); + } + + void addFinalizerIfNotSet(String attachmentName, Set existingFinalizers) { + if (existingFinalizers != null && existingFinalizers.contains(Constant.FINALIZER_NAME)) { + return; + } + + client.fetch(Attachment.class, attachmentName).ifPresent(attachment -> { + var finalizers = attachment.getMetadata().getFinalizers(); + if (finalizers == null) { + finalizers = new HashSet<>(); + attachment.getMetadata().setFinalizers(finalizers); + } + finalizers.add(Constant.FINALIZER_NAME); + client.update(attachment); + }); } } diff --git a/src/main/java/run/halo/app/infra/ExternalUrlSupplier.java b/src/main/java/run/halo/app/infra/ExternalUrlSupplier.java new file mode 100644 index 000000000..26bf8bb17 --- /dev/null +++ b/src/main/java/run/halo/app/infra/ExternalUrlSupplier.java @@ -0,0 +1,13 @@ +package run.halo.app.infra; + +import java.net.URI; +import java.util.function.Supplier; + +/** + * Represents a supplier of external url configuration. + * + * @author johnniang + */ +public interface ExternalUrlSupplier extends Supplier { + +} diff --git a/src/main/java/run/halo/app/infra/HaloPropertiesExternalUrlSupplier.java b/src/main/java/run/halo/app/infra/HaloPropertiesExternalUrlSupplier.java new file mode 100644 index 000000000..15d805be8 --- /dev/null +++ b/src/main/java/run/halo/app/infra/HaloPropertiesExternalUrlSupplier.java @@ -0,0 +1,25 @@ +package run.halo.app.infra; + +import java.net.URI; +import org.springframework.stereotype.Component; +import run.halo.app.infra.properties.HaloProperties; + +/** + * Default implementation for getting external url from halo properties. + * + * @author johnniang + */ +@Component +public class HaloPropertiesExternalUrlSupplier implements ExternalUrlSupplier { + + private final HaloProperties haloProperties; + + public HaloPropertiesExternalUrlSupplier(HaloProperties haloProperties) { + this.haloProperties = haloProperties; + } + + @Override + public URI get() { + return haloProperties.getExternalUrl(); + } +} diff --git a/src/main/java/run/halo/app/infra/properties/HaloProperties.java b/src/main/java/run/halo/app/infra/properties/HaloProperties.java index 81f19cea0..5f0538f0b 100644 --- a/src/main/java/run/halo/app/infra/properties/HaloProperties.java +++ b/src/main/java/run/halo/app/infra/properties/HaloProperties.java @@ -1,10 +1,14 @@ package run.halo.app.infra.properties; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import java.net.URI; import java.nio.file.Path; import java.util.HashSet; import java.util.Set; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; /** * @author guqing @@ -12,10 +16,15 @@ import org.springframework.boot.context.properties.ConfigurationProperties; */ @Data @ConfigurationProperties(prefix = "halo") +@Validated public class HaloProperties { + @NotNull private Path workDir; + @NotNull + private URI externalUrl; + private Set initialExtensionLocations = new HashSet<>(); /** @@ -25,7 +34,9 @@ public class HaloProperties { */ private boolean requiredExtensionDisabled; + @Valid private final ExtensionProperties extension = new ExtensionProperties(); + @Valid private final SecurityProperties security = new SecurityProperties(); } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 3e32e4061..0386c6da2 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -14,6 +14,7 @@ spring: platform: h2 halo: + external-url: "http://${server.address:localhost}:${server.port}" security: oauth2: jwt: diff --git a/src/test/java/run/halo/app/PathPrefixPredicateTest.java b/src/test/java/run/halo/app/PathPrefixPredicateTest.java index cbed800e5..1447b4dc5 100644 --- a/src/test/java/run/halo/app/PathPrefixPredicateTest.java +++ b/src/test/java/run/halo/app/PathPrefixPredicateTest.java @@ -2,13 +2,10 @@ package run.halo.app; import static org.assertj.core.api.Assertions.assertThat; -import java.util.List; import org.junit.jupiter.api.Test; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.method.HandlerTypePredicate; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; /** * Test case for api path prefix predicate. @@ -37,14 +34,4 @@ public class PathPrefixPredicateTest { } - @Test - void test() { - Flux.fromIterable(List.of(1, 2, 3)) - .flatMap(i -> { - if (i == 2) { - return Mono.empty(); - } - return Mono.just(i); - }).subscribe(System.out::println); - } } diff --git a/src/test/java/run/halo/app/infra/HaloPropertiesExternalUrlSupplierTest.java b/src/test/java/run/halo/app/infra/HaloPropertiesExternalUrlSupplierTest.java new file mode 100644 index 000000000..2fc005211 --- /dev/null +++ b/src/test/java/run/halo/app/infra/HaloPropertiesExternalUrlSupplierTest.java @@ -0,0 +1,29 @@ +package run.halo.app.infra; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.net.URI; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import run.halo.app.infra.properties.HaloProperties; + +@ExtendWith(MockitoExtension.class) +class HaloPropertiesExternalUrlSupplierTest { + + @Mock + HaloProperties haloProperties; + + @InjectMocks + HaloPropertiesExternalUrlSupplier externalUrl; + + @Test + void get() { + URI fakeUri = URI.create("fake-url"); + Mockito.when(haloProperties.getExternalUrl()).thenReturn(fakeUri); + assertEquals(fakeUri, externalUrl.get()); + } +} \ No newline at end of file diff --git a/src/test/resources/application.yaml b/src/test/resources/application.yaml index 03d071623..a45f4ea1c 100644 --- a/src/test/resources/application.yaml +++ b/src/test/resources/application.yaml @@ -14,6 +14,7 @@ spring: halo: work-dir: ${user.home}/halo-next-test + external-url: "http://${server.address:localhost}:${server.port}" security: initializer: disabled: true