From a3448adee28b954f6c20f87df500f5d32cc95761 Mon Sep 17 00:00:00 2001 From: guqing <38999863+guqing@users.noreply.github.com> Date: Tue, 18 Oct 2022 10:22:09 +0800 Subject: [PATCH] feat: add favicon head processor (#2582) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind feature /area core /milestone 2.0 #### What this PR does / why we need it: 模板渲染自动填充 Favicon 到 head 标签 #### Which issue(s) this PR fixes: Fixes #2581 #### Special notes for your reviewer: how to test it? 在 console 系统设置 -> 基础设置 填写 Favicon 后,到主题端能到看它 /cc @halo-dev/sig-halo #### Does this PR introduce a user-facing change? ```release-note 支持设置 Favicon ``` --- .../dialect/DefaultFaviconHeadProcessor.java | 46 +++++++++++++++++++ .../dialect/HaloProcessorDialectTest.java | 12 +++++ 2 files changed, 58 insertions(+) create mode 100644 src/main/java/run/halo/app/theme/dialect/DefaultFaviconHeadProcessor.java diff --git a/src/main/java/run/halo/app/theme/dialect/DefaultFaviconHeadProcessor.java b/src/main/java/run/halo/app/theme/dialect/DefaultFaviconHeadProcessor.java new file mode 100644 index 000000000..d8986ea64 --- /dev/null +++ b/src/main/java/run/halo/app/theme/dialect/DefaultFaviconHeadProcessor.java @@ -0,0 +1,46 @@ +package run.halo.app.theme.dialect; + +import lombok.AllArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import org.thymeleaf.context.ITemplateContext; +import org.thymeleaf.model.IModel; +import org.thymeleaf.model.IModelFactory; +import org.thymeleaf.processor.element.IElementModelStructureHandler; +import reactor.core.publisher.Mono; +import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; +import run.halo.app.infra.SystemSetting; + +/** + * Theme template head tag snippet injection processor for favicon. + * + * @author guqing + * @since 2.0.0 + */ +@Component +@AllArgsConstructor +public class DefaultFaviconHeadProcessor implements TemplateHeadProcessor { + + private final SystemConfigurableEnvironmentFetcher fetcher; + + @Override + public Mono process(ITemplateContext context, IModel model, + IElementModelStructureHandler structureHandler) { + return fetchBasicSetting() + .filter(basic -> StringUtils.isNotBlank(basic.getFavicon())) + .map(basic -> { + IModelFactory modelFactory = context.getModelFactory(); + model.add(modelFactory.createText(faviconSnippet(basic.getFavicon()))); + return model; + }) + .then(); + } + + private String faviconSnippet(String favicon) { + return String.format("\n", favicon); + } + + private Mono fetchBasicSetting() { + return fetcher.fetch(SystemSetting.Basic.GROUP, SystemSetting.Basic.class); + } +} diff --git a/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java b/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java index ee5960739..74c219dfc 100644 --- a/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java +++ b/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java @@ -69,6 +69,7 @@ class HaloProcessorDialectTest { Map map = new HashMap<>(); map.put("postTemplateHeadProcessor", new PostTemplateHeadProcessor(postFinder)); map.put("templateGlobalHeadProcessor", new TemplateGlobalHeadProcessor(fetcher)); + map.put("faviconHeadProcessor", new DefaultFaviconHeadProcessor(fetcher)); lenient().when(applicationContext.getBeansOfType(TemplateHeadProcessor.class)) .thenReturn(map); @@ -85,6 +86,11 @@ class HaloProcessorDialectTest { @Test void globalHeadAndFooterProcessors() { + SystemSetting.Basic basic = new SystemSetting.Basic(); + basic.setFavicon("favicon.ico"); + when(fetcher.fetch(eq(SystemSetting.Basic.GROUP), + eq(SystemSetting.Basic.class))).thenReturn(Mono.just(basic)); + Context context = getContext(); String result = templateEngine.process("index", context); @@ -95,6 +101,7 @@ class HaloProcessorDialectTest { Index +

index

@@ -124,6 +131,11 @@ class HaloProcessorDialectTest { .metadata(metadata).build(); when(postFinder.getByName(eq("fake-post"))).thenReturn(postVo); + SystemSetting.Basic basic = new SystemSetting.Basic(); + basic.setFavicon(null); + when(fetcher.fetch(eq(SystemSetting.Basic.GROUP), + eq(SystemSetting.Basic.class))).thenReturn(Mono.just(basic)); + String result = templateEngine.process("post", context); assertThat(result).isEqualTo("""