mirror of https://github.com/halo-dev/halo
Add support for configuring external URL online
parent
b309bc532b
commit
e9011eb3ec
|
@ -71,6 +71,7 @@ public class SystemSetting {
|
||||||
String logo;
|
String logo;
|
||||||
String favicon;
|
String favicon;
|
||||||
String language;
|
String language;
|
||||||
|
String externalUrl;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public Optional<Locale> useSystemLocale() {
|
public Optional<Locale> useSystemLocale() {
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
package run.halo.app.infra;
|
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
|
||||||
import org.springframework.http.HttpRequest;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
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;
|
|
||||||
|
|
||||||
private final WebFluxProperties webFluxProperties;
|
|
||||||
|
|
||||||
public HaloPropertiesExternalUrlSupplier(HaloProperties haloProperties,
|
|
||||||
WebFluxProperties webFluxProperties) {
|
|
||||||
this.haloProperties = haloProperties;
|
|
||||||
this.webFluxProperties = webFluxProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public URI get() {
|
|
||||||
if (!haloProperties.isUseAbsolutePermalink()) {
|
|
||||||
return URI.create(getBasePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return haloProperties.getExternalUrl().toURI();
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public URL getURL(HttpRequest request) {
|
|
||||||
var externalUrl = haloProperties.getExternalUrl();
|
|
||||||
if (externalUrl == null) {
|
|
||||||
try {
|
|
||||||
externalUrl = request.getURI().resolve(getBasePath()).toURL();
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
throw new RuntimeException("Cannot parse request URI to URL.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return externalUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public URL getRaw() {
|
|
||||||
return haloProperties.getExternalUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getBasePath() {
|
|
||||||
var basePath = webFluxProperties.getBasePath();
|
|
||||||
if (!StringUtils.hasText(basePath)) {
|
|
||||||
basePath = "/";
|
|
||||||
}
|
|
||||||
return basePath;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
package run.halo.app.infra;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.time.Duration;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.http.HttpRequest;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import reactor.core.Exceptions;
|
||||||
|
import run.halo.app.infra.properties.HaloProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation for getting external url from system config first, halo properties second.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
class SystemConfigFirstExternalUrlSupplier implements ExternalUrlSupplier {
|
||||||
|
|
||||||
|
private final HaloProperties haloProperties;
|
||||||
|
|
||||||
|
private final WebFluxProperties webFluxProperties;
|
||||||
|
|
||||||
|
private final SystemConfigurableEnvironmentFetcher systemConfigFetcher;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private URL externalUrl;
|
||||||
|
|
||||||
|
public SystemConfigFirstExternalUrlSupplier(HaloProperties haloProperties,
|
||||||
|
WebFluxProperties webFluxProperties,
|
||||||
|
SystemConfigurableEnvironmentFetcher systemConfigFetcher) {
|
||||||
|
this.haloProperties = haloProperties;
|
||||||
|
this.webFluxProperties = webFluxProperties;
|
||||||
|
this.systemConfigFetcher = systemConfigFetcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
void onExtensionInitialized(ExtensionInitializedEvent ignored) {
|
||||||
|
systemConfigFetcher.getBasic()
|
||||||
|
.mapNotNull(SystemSetting.Basic::getExternalUrl)
|
||||||
|
.filter(StringUtils::hasText)
|
||||||
|
.doOnNext(externalUrlString -> {
|
||||||
|
try {
|
||||||
|
this.externalUrl = URI.create(externalUrlString).toURL();
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
log.error("""
|
||||||
|
Cannot parse external URL {} from system config. Fallback to default \
|
||||||
|
external URL supplier from properties.\
|
||||||
|
""", externalUrlString, e);
|
||||||
|
// For continuing the application startup, we need to return null here.
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.blockOptional(Duration.ofSeconds(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URI get() {
|
||||||
|
try {
|
||||||
|
if (externalUrl != null) {
|
||||||
|
return externalUrl.toURI();
|
||||||
|
}
|
||||||
|
if (!haloProperties.isUseAbsolutePermalink()) {
|
||||||
|
return URI.create(getBasePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
return haloProperties.getExternalUrl().toURI();
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw Exceptions.propagate(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getURL(HttpRequest request) {
|
||||||
|
if (this.externalUrl != null) {
|
||||||
|
return this.externalUrl;
|
||||||
|
}
|
||||||
|
var externalUrl = haloProperties.getExternalUrl();
|
||||||
|
if (externalUrl != null) {
|
||||||
|
return externalUrl;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
externalUrl = request.getURI().resolve(getBasePath()).toURL();
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new RuntimeException("Cannot parse request URI to URL.", e);
|
||||||
|
}
|
||||||
|
return externalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public URL getRaw() {
|
||||||
|
return externalUrl != null ? externalUrl : haloProperties.getExternalUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getBasePath() {
|
||||||
|
var basePath = webFluxProperties.getBasePath();
|
||||||
|
if (!StringUtils.hasText(basePath)) {
|
||||||
|
basePath = "/";
|
||||||
|
}
|
||||||
|
return basePath;
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,17 +61,17 @@ public class SystemConfigurableEnvironmentFetcher implements Reconciler<Reconcil
|
||||||
|
|
||||||
public Mono<SystemSetting.Basic> getBasic() {
|
public Mono<SystemSetting.Basic> getBasic() {
|
||||||
return fetch(SystemSetting.Basic.GROUP, SystemSetting.Basic.class)
|
return fetch(SystemSetting.Basic.GROUP, SystemSetting.Basic.class)
|
||||||
.switchIfEmpty(Mono.just(new SystemSetting.Basic()));
|
.switchIfEmpty(Mono.fromSupplier(SystemSetting.Basic::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mono<SystemSetting.Comment> fetchComment() {
|
public Mono<SystemSetting.Comment> fetchComment() {
|
||||||
return fetch(SystemSetting.Comment.GROUP, SystemSetting.Comment.class)
|
return fetch(SystemSetting.Comment.GROUP, SystemSetting.Comment.class)
|
||||||
.switchIfEmpty(Mono.just(new SystemSetting.Comment()));
|
.switchIfEmpty(Mono.fromSupplier(SystemSetting.Comment::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mono<SystemSetting.Post> fetchPost() {
|
public Mono<SystemSetting.Post> fetchPost() {
|
||||||
return fetch(SystemSetting.Post.GROUP, SystemSetting.Post.class)
|
return fetch(SystemSetting.Post.GROUP, SystemSetting.Post.class)
|
||||||
.switchIfEmpty(Mono.just(new SystemSetting.Post()));
|
.switchIfEmpty(Mono.fromSupplier(SystemSetting.Post::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mono<SystemSetting.ThemeRouteRules> fetchRouteRules() {
|
public Mono<SystemSetting.ThemeRouteRules> fetchRouteRules() {
|
||||||
|
@ -123,15 +123,17 @@ public class SystemConfigurableEnvironmentFetcher implements Reconciler<Reconcil
|
||||||
data.forEach((group, dataValue) -> {
|
data.forEach((group, dataValue) -> {
|
||||||
// https://www.rfc-editor.org/rfc/rfc7386
|
// https://www.rfc-editor.org/rfc/rfc7386
|
||||||
String defaultV = copiedDefault.get(group);
|
String defaultV = copiedDefault.get(group);
|
||||||
String newValue;
|
String newValue = null;
|
||||||
if (dataValue == null) {
|
if (dataValue == null) {
|
||||||
if (copiedDefault.containsKey(group)) {
|
if (!copiedDefault.containsKey(group)) {
|
||||||
newValue = null;
|
|
||||||
} else {
|
|
||||||
newValue = defaultV;
|
newValue = defaultV;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newValue = mergeRemappingFunction(dataValue, defaultV);
|
if (copiedDefault.containsKey(group)) {
|
||||||
|
newValue = mergeRemappingFunction(dataValue, defaultV);
|
||||||
|
} else {
|
||||||
|
newValue = dataValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newValue == null) {
|
if (newValue == null) {
|
||||||
|
@ -195,20 +197,18 @@ public class SystemConfigurableEnvironmentFetcher implements Reconciler<Reconcil
|
||||||
* @return a new {@link ConfigMap} named <code>system</code> by json merge patch.
|
* @return a new {@link ConfigMap} named <code>system</code> by json merge patch.
|
||||||
*/
|
*/
|
||||||
private Mono<ConfigMap> loadConfigMapInternal() {
|
private Mono<ConfigMap> loadConfigMapInternal() {
|
||||||
Mono<ConfigMap> mapMono =
|
var defaultConfigMono =
|
||||||
extensionClient.fetch(ConfigMap.class, SystemSetting.SYSTEM_CONFIG_DEFAULT);
|
extensionClient.fetch(ConfigMap.class, SystemSetting.SYSTEM_CONFIG_DEFAULT);
|
||||||
if (mapMono == null) {
|
var configMono = extensionClient.fetch(ConfigMap.class, SystemSetting.SYSTEM_CONFIG);
|
||||||
return Mono.empty();
|
return defaultConfigMono.flatMap(defaultConfig -> configMono.map(
|
||||||
}
|
config -> {
|
||||||
return mapMono.flatMap(systemDefault ->
|
Map<String, String> defaultData = defaultConfig.getData();
|
||||||
extensionClient.fetch(ConfigMap.class, SystemSetting.SYSTEM_CONFIG)
|
Map<String, String> data = config.getData();
|
||||||
.map(system -> {
|
|
||||||
Map<String, String> defaultData = systemDefault.getData();
|
|
||||||
Map<String, String> data = system.getData();
|
|
||||||
Map<String, String> mergedData = mergeData(defaultData, data);
|
Map<String, String> mergedData = mergeData(defaultData, data);
|
||||||
system.setData(mergedData);
|
config.setData(mergedData);
|
||||||
return system;
|
return config;
|
||||||
})
|
})
|
||||||
.switchIfEmpty(Mono.just(systemDefault)));
|
.defaultIfEmpty(defaultConfig)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.extension.ConfigMap;
|
import run.halo.app.extension.ConfigMap;
|
||||||
|
import run.halo.app.infra.ExternalUrlSupplier;
|
||||||
import run.halo.app.infra.InitializationStateGetter;
|
import run.halo.app.infra.InitializationStateGetter;
|
||||||
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
|
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
|
||||||
import run.halo.app.infra.SystemSetting;
|
import run.halo.app.infra.SystemSetting;
|
||||||
|
@ -36,20 +37,24 @@ public class GlobalInfoServiceImpl implements GlobalInfoService {
|
||||||
private final ObjectProvider<SystemConfigurableEnvironmentFetcher>
|
private final ObjectProvider<SystemConfigurableEnvironmentFetcher>
|
||||||
systemConfigFetcher;
|
systemConfigFetcher;
|
||||||
|
|
||||||
|
private final ExternalUrlSupplier externalUrl;
|
||||||
|
|
||||||
public GlobalInfoServiceImpl(HaloProperties haloProperties,
|
public GlobalInfoServiceImpl(HaloProperties haloProperties,
|
||||||
AuthProviderService authProviderService,
|
AuthProviderService authProviderService,
|
||||||
InitializationStateGetter initializationStateGetter,
|
InitializationStateGetter initializationStateGetter,
|
||||||
ObjectProvider<SystemConfigurableEnvironmentFetcher> systemConfigFetcher) {
|
ObjectProvider<SystemConfigurableEnvironmentFetcher> systemConfigFetcher,
|
||||||
|
ExternalUrlSupplier externalUrl) {
|
||||||
this.haloProperties = haloProperties;
|
this.haloProperties = haloProperties;
|
||||||
this.authProviderService = authProviderService;
|
this.authProviderService = authProviderService;
|
||||||
this.initializationStateGetter = initializationStateGetter;
|
this.initializationStateGetter = initializationStateGetter;
|
||||||
this.systemConfigFetcher = systemConfigFetcher;
|
this.systemConfigFetcher = systemConfigFetcher;
|
||||||
|
this.externalUrl = externalUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<GlobalInfo> getGlobalInfo() {
|
public Mono<GlobalInfo> getGlobalInfo() {
|
||||||
final var info = new GlobalInfo();
|
final var info = new GlobalInfo();
|
||||||
info.setExternalUrl(haloProperties.getExternalUrl());
|
info.setExternalUrl(externalUrl.getRaw());
|
||||||
info.setUseAbsolutePermalink(haloProperties.isUseAbsolutePermalink());
|
info.setUseAbsolutePermalink(haloProperties.isUseAbsolutePermalink());
|
||||||
info.setLocale(Locale.getDefault());
|
info.setLocale(Locale.getDefault());
|
||||||
info.setTimeZone(TimeZone.getDefault());
|
info.setTimeZone(TimeZone.getDefault());
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
package run.halo.app.infra;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
import static org.mockito.Mockito.lenient;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URL;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.InjectMocks;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
|
||||||
import org.springframework.http.HttpRequest;
|
|
||||||
import run.halo.app.infra.properties.HaloProperties;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
class HaloPropertiesExternalUrlSupplierTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
HaloProperties haloProperties;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
WebFluxProperties webFluxProperties;
|
|
||||||
|
|
||||||
@InjectMocks
|
|
||||||
HaloPropertiesExternalUrlSupplier externalUrl;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getURIWhenUsingAbsolutePermalink() throws MalformedURLException {
|
|
||||||
var fakeUri = URI.create("https://halo.run/fake");
|
|
||||||
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
|
||||||
when(haloProperties.isUseAbsolutePermalink()).thenReturn(true);
|
|
||||||
|
|
||||||
assertEquals(fakeUri, externalUrl.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getURIWhenBasePathSetAndNotUsingAbsolutePermalink() throws MalformedURLException {
|
|
||||||
when(webFluxProperties.getBasePath()).thenReturn("/blog");
|
|
||||||
when(haloProperties.isUseAbsolutePermalink()).thenReturn(false);
|
|
||||||
|
|
||||||
assertEquals(URI.create("/blog"), externalUrl.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getURIWhenBasePathSetAndUsingAbsolutePermalink() throws MalformedURLException {
|
|
||||||
var fakeUri = URI.create("https://halo.run/fake");
|
|
||||||
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
|
||||||
lenient().when(webFluxProperties.getBasePath()).thenReturn("/blog");
|
|
||||||
when(haloProperties.isUseAbsolutePermalink()).thenReturn(true);
|
|
||||||
|
|
||||||
assertEquals(URI.create("https://halo.run/fake"), externalUrl.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getURIWhenUsingRelativePermalink() throws MalformedURLException {
|
|
||||||
when(haloProperties.isUseAbsolutePermalink()).thenReturn(false);
|
|
||||||
|
|
||||||
assertEquals(URI.create("/"), externalUrl.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getURLWhenExternalURLProvided() throws MalformedURLException {
|
|
||||||
var fakeUri = URI.create("https://halo.run/fake");
|
|
||||||
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
|
||||||
var mockRequest = mock(HttpRequest.class);
|
|
||||||
var url = externalUrl.getURL(mockRequest);
|
|
||||||
assertEquals(fakeUri.toURL(), url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getURLWhenExternalURLAbsent() throws MalformedURLException {
|
|
||||||
var fakeUri = URI.create("https://localhost/fake");
|
|
||||||
when(haloProperties.getExternalUrl()).thenReturn(null);
|
|
||||||
var mockRequest = mock(HttpRequest.class);
|
|
||||||
when(mockRequest.getURI()).thenReturn(fakeUri);
|
|
||||||
var url = externalUrl.getURL(mockRequest);
|
|
||||||
assertEquals(new URL("https://localhost/"), url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getURLWhenBasePathSetAndExternalURLProvided() throws MalformedURLException {
|
|
||||||
var fakeUri = URI.create("https://localhost/fake");
|
|
||||||
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
|
||||||
lenient().when(webFluxProperties.getBasePath()).thenReturn("/blog");
|
|
||||||
var mockRequest = mock(HttpRequest.class);
|
|
||||||
lenient().when(mockRequest.getURI()).thenReturn(fakeUri);
|
|
||||||
var url = externalUrl.getURL(mockRequest);
|
|
||||||
assertEquals(new URL("https://localhost/fake"), url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getURLWhenBasePathSetAndExternalURLAbsent() throws MalformedURLException {
|
|
||||||
var fakeUri = URI.create("https://localhost/fake");
|
|
||||||
when(haloProperties.getExternalUrl()).thenReturn(null);
|
|
||||||
when(webFluxProperties.getBasePath()).thenReturn("/blog");
|
|
||||||
var mockRequest = mock(HttpRequest.class);
|
|
||||||
when(mockRequest.getURI()).thenReturn(fakeUri);
|
|
||||||
var url = externalUrl.getURL(mockRequest);
|
|
||||||
assertEquals(new URL("https://localhost/blog"), url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getRaw() throws MalformedURLException {
|
|
||||||
var fakeUri = URI.create("http://localhost/fake");
|
|
||||||
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
|
||||||
assertEquals(fakeUri.toURL(), externalUrl.getRaw());
|
|
||||||
|
|
||||||
when(haloProperties.getExternalUrl()).thenReturn(null);
|
|
||||||
assertNull(externalUrl.getRaw());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
package run.halo.app.infra;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.mockito.Mockito.lenient;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
|
||||||
|
import org.springframework.http.HttpRequest;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import run.halo.app.infra.properties.HaloProperties;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class SystemConfigFirstExternalUrlSupplierTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
HaloProperties haloProperties;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
WebFluxProperties webFluxProperties;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
SystemConfigurableEnvironmentFetcher systemConfigFetcher;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
SystemConfigFirstExternalUrlSupplier externalUrl;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class HaloPropertiesSupplier {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
when(systemConfigFetcher.getBasic()).thenReturn(Mono.empty());
|
||||||
|
externalUrl.onExtensionInitialized(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getURIWhenUsingAbsolutePermalink() throws MalformedURLException {
|
||||||
|
var fakeUri = URI.create("https://halo.run/fake");
|
||||||
|
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
||||||
|
when(haloProperties.isUseAbsolutePermalink()).thenReturn(true);
|
||||||
|
|
||||||
|
assertEquals(fakeUri, externalUrl.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getURIWhenBasePathSetAndNotUsingAbsolutePermalink() throws MalformedURLException {
|
||||||
|
when(webFluxProperties.getBasePath()).thenReturn("/blog");
|
||||||
|
when(haloProperties.isUseAbsolutePermalink()).thenReturn(false);
|
||||||
|
|
||||||
|
assertEquals(URI.create("/blog"), externalUrl.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getURIWhenBasePathSetAndUsingAbsolutePermalink() throws MalformedURLException {
|
||||||
|
var fakeUri = URI.create("https://halo.run/fake");
|
||||||
|
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
||||||
|
lenient().when(webFluxProperties.getBasePath()).thenReturn("/blog");
|
||||||
|
when(haloProperties.isUseAbsolutePermalink()).thenReturn(true);
|
||||||
|
|
||||||
|
assertEquals(URI.create("https://halo.run/fake"), externalUrl.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getURIWhenUsingRelativePermalink() throws MalformedURLException {
|
||||||
|
when(haloProperties.isUseAbsolutePermalink()).thenReturn(false);
|
||||||
|
|
||||||
|
assertEquals(URI.create("/"), externalUrl.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getURLWhenExternalURLProvided() throws MalformedURLException {
|
||||||
|
var fakeUri = URI.create("https://halo.run/fake");
|
||||||
|
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
||||||
|
var mockRequest = mock(HttpRequest.class);
|
||||||
|
var url = externalUrl.getURL(mockRequest);
|
||||||
|
assertEquals(fakeUri.toURL(), url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getURLWhenExternalURLAbsent() throws MalformedURLException {
|
||||||
|
var fakeUri = URI.create("https://localhost/fake");
|
||||||
|
when(haloProperties.getExternalUrl()).thenReturn(null);
|
||||||
|
var mockRequest = mock(HttpRequest.class);
|
||||||
|
when(mockRequest.getURI()).thenReturn(fakeUri);
|
||||||
|
var url = externalUrl.getURL(mockRequest);
|
||||||
|
assertEquals(new URL("https://localhost/"), url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getURLWhenBasePathSetAndExternalURLProvided() throws MalformedURLException {
|
||||||
|
var fakeUri = URI.create("https://localhost/fake");
|
||||||
|
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
||||||
|
lenient().when(webFluxProperties.getBasePath()).thenReturn("/blog");
|
||||||
|
var mockRequest = mock(HttpRequest.class);
|
||||||
|
lenient().when(mockRequest.getURI()).thenReturn(fakeUri);
|
||||||
|
var url = externalUrl.getURL(mockRequest);
|
||||||
|
assertEquals(new URL("https://localhost/fake"), url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getURLWhenBasePathSetAndExternalURLAbsent() throws MalformedURLException {
|
||||||
|
var fakeUri = URI.create("https://localhost/fake");
|
||||||
|
when(haloProperties.getExternalUrl()).thenReturn(null);
|
||||||
|
when(webFluxProperties.getBasePath()).thenReturn("/blog");
|
||||||
|
var mockRequest = mock(HttpRequest.class);
|
||||||
|
when(mockRequest.getURI()).thenReturn(fakeUri);
|
||||||
|
var url = externalUrl.getURL(mockRequest);
|
||||||
|
assertEquals(new URL("https://localhost/blog"), url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getRaw() throws MalformedURLException {
|
||||||
|
var fakeUri = URI.create("http://localhost/fake");
|
||||||
|
when(haloProperties.getExternalUrl()).thenReturn(fakeUri.toURL());
|
||||||
|
assertEquals(fakeUri.toURL(), externalUrl.getRaw());
|
||||||
|
|
||||||
|
when(haloProperties.getExternalUrl()).thenReturn(null);
|
||||||
|
assertNull(externalUrl.getRaw());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class SystemConfigSupplier {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldGetUrlCorrectly() throws Exception {
|
||||||
|
var basic = new SystemSetting.Basic();
|
||||||
|
basic.setExternalUrl("https://www.halo.run");
|
||||||
|
when(systemConfigFetcher.getBasic()).thenReturn(Mono.just(basic));
|
||||||
|
externalUrl.onExtensionInitialized(null);
|
||||||
|
assertEquals(URI.create("https://www.halo.run").toURL(), externalUrl.getRaw());
|
||||||
|
assertEquals(URI.create("https://www.halo.run"), externalUrl.get());
|
||||||
|
|
||||||
|
var mockRequest = mock(HttpRequest.class);
|
||||||
|
assertEquals(URI.create("https://www.halo.run").toURL(),
|
||||||
|
externalUrl.getURL(mockRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue