feat: support obtaining the configuration of halo.external-url for themes and plugins (#2714)

#### What type of PR is this?
/kind improvement
/area core
/milestone 2.0

#### What this PR does / why we need it:
主题和插件支持获取 `halo.external-url` 配置信息

#### Which issue(s) this PR fixes:

Fixes #2711
#### Special notes for your reviewer:
how to test it?
1. 在主题中使用`<p th:text="${site.url}"></p>` 可以正确显示
2. 在插件中可以依赖注入 ExternalUrlSupplier

/cc @halo-dev/sig-halo 
#### Does this PR introduce a user-facing change?

```release-note
主题和插件支持获取外部访问地址配置
```
pull/2718/head^2
guqing 2022-11-18 14:30:27 +08:00 committed by GitHub
parent 9e5c6a45c9
commit eeb9c4dc7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 5 deletions

View File

@ -6,6 +6,7 @@ import org.springframework.stereotype.Component;
import run.halo.app.extension.DefaultSchemeManager; import run.halo.app.extension.DefaultSchemeManager;
import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.ExtensionClient;
import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.infra.ExternalUrlSupplier;
/** /**
* <p>This {@link SharedApplicationContextHolder} class is used to hold a singleton instance of * <p>This {@link SharedApplicationContextHolder} class is used to hold a singleton instance of
@ -61,6 +62,8 @@ public class SharedApplicationContextHolder {
DefaultSchemeManager defaultSchemeManager = DefaultSchemeManager defaultSchemeManager =
rootApplicationContext.getBean(DefaultSchemeManager.class); rootApplicationContext.getBean(DefaultSchemeManager.class);
beanFactory.registerSingleton("schemeManager", defaultSchemeManager); beanFactory.registerSingleton("schemeManager", defaultSchemeManager);
beanFactory.registerSingleton("externalUrlSupplier",
rootApplicationContext.getBean(ExternalUrlSupplier.class));
// TODO add more shared instance here // TODO add more shared instance here
return sharedApplicationContext; return sharedApplicationContext;

View File

@ -1,9 +1,11 @@
package run.halo.app.theme; package run.halo.app.theme;
import java.util.Map; import java.util.Map;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import run.halo.app.infra.ExternalUrlSupplier;
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
import run.halo.app.theme.finders.vo.SiteSettingVo; import run.halo.app.theme.finders.vo.SiteSettingVo;
@ -14,20 +16,19 @@ import run.halo.app.theme.finders.vo.SiteSettingVo;
* @since 2.0.0 * @since 2.0.0
*/ */
@Component @Component
@AllArgsConstructor
public class SiteSettingVariablesAcquirer implements ViewContextBasedVariablesAcquirer { public class SiteSettingVariablesAcquirer implements ViewContextBasedVariablesAcquirer {
private final SystemConfigurableEnvironmentFetcher environmentFetcher; private final SystemConfigurableEnvironmentFetcher environmentFetcher;
private final ExternalUrlSupplier externalUrlSupplier;
public SiteSettingVariablesAcquirer(SystemConfigurableEnvironmentFetcher environmentFetcher) {
this.environmentFetcher = environmentFetcher;
}
@Override @Override
public Mono<Map<String, Object>> acquire(ServerWebExchange exchange) { public Mono<Map<String, Object>> acquire(ServerWebExchange exchange) {
return environmentFetcher.getConfigMap() return environmentFetcher.getConfigMap()
.filter(configMap -> configMap.getData() != null) .filter(configMap -> configMap.getData() != null)
.map(configMap -> { .map(configMap -> {
SiteSettingVo siteSettingVo = SiteSettingVo.from(configMap); SiteSettingVo siteSettingVo = SiteSettingVo.from(configMap)
.withUrl(externalUrlSupplier.get());
return Map.of("site", siteSettingVo); return Map.of("site", siteSettingVo);
}); });
} }

View File

@ -1,8 +1,10 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.net.URI;
import java.util.Map; import java.util.Map;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import lombok.With;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import run.halo.app.extension.ConfigMap; import run.halo.app.extension.ConfigMap;
import run.halo.app.infra.SystemSetting; import run.halo.app.infra.SystemSetting;
@ -20,6 +22,9 @@ public class SiteSettingVo {
String title; String title;
@With
URI url;
String subtitle; String subtitle;
String logo; String logo;

View File

@ -0,0 +1,59 @@
package run.halo.app.theme;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
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 org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import run.halo.app.extension.ConfigMap;
import run.halo.app.infra.ExternalUrlSupplier;
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
import run.halo.app.theme.finders.vo.SiteSettingVo;
/**
* Tests for {@link SiteSettingVariablesAcquirer}.
*
* @author guqing
* @since 2.0.0
*/
@ExtendWith(MockitoExtension.class)
public class SiteSettingVariablesAcquirerTest {
@Mock
private ExternalUrlSupplier externalUrlSupplier;
@Mock
private SystemConfigurableEnvironmentFetcher environmentFetcher;
@InjectMocks
private SiteSettingVariablesAcquirer siteSettingVariablesAcquirer;
@Test
void acquire() throws URISyntaxException {
ConfigMap configMap = new ConfigMap();
configMap.setData(Map.of());
URI uri = new URI("https://halo.run");
when(externalUrlSupplier.get()).thenReturn(uri);
when(environmentFetcher.getConfigMap()).thenReturn(Mono.just(configMap));
siteSettingVariablesAcquirer.acquire(Mockito.mock(ServerWebExchange.class))
.as(StepVerifier::create)
.consumeNextWith(result -> {
assertThat(result).containsKey("site");
assertThat(result.get("site")).isInstanceOf(SiteSettingVo.class);
assertThat((SiteSettingVo) result.get("site"))
.extracting(SiteSettingVo::getUrl)
.isEqualTo(uri);
})
.verifyComplete();
}
}