mirror of https://github.com/halo-dev/halo
refactor: optimize the usage of comment widget extension point (#4249)
#### What type of PR is this? /kind improvement /area core /milestone 2.8.x #### What this PR does / why we need it: 优化评论扩展点的使用方式 how to test it? 测试评论插件是否正常可用 #### Does this PR introduce a user-facing change? ```release-note 优化评论扩展点的使用方式 ```pull/4270/head
parent
5eb9b68209
commit
133e54106d
|
@ -1,11 +1,14 @@
|
||||||
package run.halo.app.plugin.extensionpoint;
|
package run.halo.app.plugin.extensionpoint;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.pf4j.ExtensionPoint;
|
import org.pf4j.ExtensionPoint;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
@ -32,14 +35,17 @@ public class DefaultExtensionGetter implements ExtensionGetter {
|
||||||
.switchIfEmpty(Mono.just(ExtensionPointEnabled.EMPTY))
|
.switchIfEmpty(Mono.just(ExtensionPointEnabled.EMPTY))
|
||||||
.mapNotNull(enabled -> {
|
.mapNotNull(enabled -> {
|
||||||
var implClassNames = enabled.getOrDefault(extensionPoint.getName(), Set.of());
|
var implClassNames = enabled.getOrDefault(extensionPoint.getName(), Set.of());
|
||||||
return pluginManager.getExtensions(extensionPoint)
|
List<T> allExtensions = getAllExtensions(extensionPoint);
|
||||||
|
if (allExtensions.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return allExtensions
|
||||||
.stream()
|
.stream()
|
||||||
.filter(impl -> implClassNames.contains(impl.getClass().getName()))
|
.filter(impl -> implClassNames.contains(impl.getClass().getName()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
// Fallback to local implementation of the extension point.
|
// Fallback to local implementation of the extension point.
|
||||||
// This will happen when no proper configuration is found.
|
// This will happen when no proper configuration is found.
|
||||||
.orElseGet(() ->
|
.orElseGet(() -> allExtensions.get(0));
|
||||||
applicationContext.getBeanProvider(extensionPoint).getIfAvailable());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,14 +80,21 @@ public class DefaultExtensionGetter implements ExtensionGetter {
|
||||||
if (type == ExtensionPointDefinition.ExtensionPointType.SINGLETON) {
|
if (type == ExtensionPointDefinition.ExtensionPointType.SINGLETON) {
|
||||||
return getEnabledExtension(extensionPoint).flux();
|
return getEnabledExtension(extensionPoint).flux();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO If the type is sortable, may need to process the returned order.
|
||||||
|
return Flux.fromIterable(getAllExtensions(extensionPoint));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
<T extends ExtensionPoint> List<T> getAllExtensions(Class<T> extensionPoint) {
|
||||||
Stream<T> pluginExtsStream = pluginManager.getExtensions(extensionPoint)
|
Stream<T> pluginExtsStream = pluginManager.getExtensions(extensionPoint)
|
||||||
.stream();
|
.stream();
|
||||||
Stream<T> systemExtsStream = applicationContext.getBeanProvider(extensionPoint)
|
Stream<T> systemExtsStream = applicationContext.getBeanProvider(extensionPoint)
|
||||||
.orderedStream();
|
.orderedStream();
|
||||||
// TODO If the type is sortable, may need to process the returned order.
|
return Stream.concat(systemExtsStream, pluginExtsStream)
|
||||||
return Flux.just(pluginExtsStream, systemExtsStream)
|
.sorted(new AnnotationAwareOrderComparator())
|
||||||
.flatMap(Flux::fromStream);
|
.toList();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<ExtensionPointDefinition> fetchExtensionPointDefinition(
|
Mono<ExtensionPointDefinition> fetchExtensionPointDefinition(
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package run.halo.app.theme.dialect;
|
package run.halo.app.theme.dialect;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.thymeleaf.context.ITemplateContext;
|
import org.thymeleaf.context.ITemplateContext;
|
||||||
import org.thymeleaf.model.IProcessableElementTag;
|
import org.thymeleaf.model.IProcessableElementTag;
|
||||||
|
@ -8,7 +7,7 @@ import org.thymeleaf.processor.element.AbstractElementTagProcessor;
|
||||||
import org.thymeleaf.processor.element.IElementTagStructureHandler;
|
import org.thymeleaf.processor.element.IElementTagStructureHandler;
|
||||||
import org.thymeleaf.spring6.context.SpringContextUtils;
|
import org.thymeleaf.spring6.context.SpringContextUtils;
|
||||||
import org.thymeleaf.templatemode.TemplateMode;
|
import org.thymeleaf.templatemode.TemplateMode;
|
||||||
import run.halo.app.plugin.ExtensionComponentsFinder;
|
import run.halo.app.plugin.extensionpoint.ExtensionGetter;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,15 +43,15 @@ public class CommentElementTagProcessor extends AbstractElementTagProcessor {
|
||||||
protected void doProcess(ITemplateContext context, IProcessableElementTag tag,
|
protected void doProcess(ITemplateContext context, IProcessableElementTag tag,
|
||||||
IElementTagStructureHandler structureHandler) {
|
IElementTagStructureHandler structureHandler) {
|
||||||
final ApplicationContext appCtx = SpringContextUtils.getApplicationContext(context);
|
final ApplicationContext appCtx = SpringContextUtils.getApplicationContext(context);
|
||||||
ExtensionComponentsFinder componentsFinder =
|
ExtensionGetter extensionGetter = appCtx.getBean(ExtensionGetter.class);
|
||||||
appCtx.getBean(ExtensionComponentsFinder.class);
|
CommentWidget commentWidget =
|
||||||
List<CommentWidget> commentWidgets = componentsFinder.getExtensions(CommentWidget.class);
|
extensionGetter.getEnabledExtensionByDefinition(CommentWidget.class)
|
||||||
if (commentWidgets.isEmpty()) {
|
.next()
|
||||||
|
.block();
|
||||||
|
if (commentWidget == null) {
|
||||||
structureHandler.replaceWith("", false);
|
structureHandler.replaceWith("", false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO if find more than one comment widget, query CommentWidget setting to decide which
|
commentWidget.render(context, tag, structureHandler);
|
||||||
// one to use.
|
|
||||||
commentWidgets.get(0).render(context, tag, structureHandler);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ spec:
|
||||||
className: run.halo.app.theme.ReactivePostContentHandler
|
className: run.halo.app.theme.ReactivePostContentHandler
|
||||||
displayName: ReactivePostContentHandler
|
displayName: ReactivePostContentHandler
|
||||||
type: MULTI_INSTANCE
|
type: MULTI_INSTANCE
|
||||||
description: "Provides a way to extend the post content to be displayed in the theme-side."
|
description: "Provides a way to extend the post content to be displayed on the theme-side."
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: plugin.halo.run/v1alpha1
|
apiVersion: plugin.halo.run/v1alpha1
|
||||||
|
@ -29,4 +29,15 @@ spec:
|
||||||
className: run.halo.app.theme.ReactiveSinglePageContentHandler
|
className: run.halo.app.theme.ReactiveSinglePageContentHandler
|
||||||
displayName: ReactiveSinglePageContentHandler
|
displayName: ReactiveSinglePageContentHandler
|
||||||
type: MULTI_INSTANCE
|
type: MULTI_INSTANCE
|
||||||
description: "Provides a way to extend the single page content to be displayed in the theme-side."
|
description: "Provides a way to extend the single page content to be displayed on the theme-side."
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: plugin.halo.run/v1alpha1
|
||||||
|
kind: ExtensionPointDefinition
|
||||||
|
metadata:
|
||||||
|
name: comment-widget
|
||||||
|
spec:
|
||||||
|
className: run.halo.app.theme.dialect.CommentWidget
|
||||||
|
displayName: CommentWidget
|
||||||
|
type: SINGLETON
|
||||||
|
description: "Provides an extension point for the comment widget on the theme-side."
|
||||||
|
|
|
@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -24,7 +23,9 @@ import org.thymeleaf.spring6.expression.ThymeleafEvaluationContext;
|
||||||
import org.thymeleaf.templateresolver.StringTemplateResolver;
|
import org.thymeleaf.templateresolver.StringTemplateResolver;
|
||||||
import org.thymeleaf.templateresource.ITemplateResource;
|
import org.thymeleaf.templateresource.ITemplateResource;
|
||||||
import org.thymeleaf.templateresource.StringTemplateResource;
|
import org.thymeleaf.templateresource.StringTemplateResource;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
import run.halo.app.plugin.ExtensionComponentsFinder;
|
import run.halo.app.plugin.ExtensionComponentsFinder;
|
||||||
|
import run.halo.app.plugin.extensionpoint.ExtensionGetter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link CommentElementTagProcessor}.
|
* Tests for {@link CommentElementTagProcessor}.
|
||||||
|
@ -41,7 +42,7 @@ class CommentElementTagProcessorTest {
|
||||||
private ApplicationContext applicationContext;
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private ExtensionComponentsFinder componentsFinder;
|
private ExtensionGetter extensionGetter;
|
||||||
|
|
||||||
private TemplateEngine templateEngine;
|
private TemplateEngine templateEngine;
|
||||||
|
|
||||||
|
@ -51,14 +52,16 @@ class CommentElementTagProcessorTest {
|
||||||
templateEngine = new TemplateEngine();
|
templateEngine = new TemplateEngine();
|
||||||
templateEngine.setDialects(Set.of(haloProcessorDialect, new SpringStandardDialect()));
|
templateEngine.setDialects(Set.of(haloProcessorDialect, new SpringStandardDialect()));
|
||||||
templateEngine.addTemplateResolver(new TestTemplateResolver());
|
templateEngine.addTemplateResolver(new TestTemplateResolver());
|
||||||
when(applicationContext.getBean(eq(ExtensionComponentsFinder.class)))
|
when(applicationContext.getBean(eq(ExtensionGetter.class)))
|
||||||
.thenReturn(componentsFinder);
|
.thenReturn(extensionGetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void doProcess() {
|
void doProcess() {
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
|
|
||||||
|
when(extensionGetter.getEnabledExtensionByDefinition(eq(CommentWidget.class)))
|
||||||
|
.thenReturn(Flux.empty());
|
||||||
String result = templateEngine.process("commentWidget", context);
|
String result = templateEngine.process("commentWidget", context);
|
||||||
assertThat(result).isEqualTo("""
|
assertThat(result).isEqualTo("""
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
@ -70,8 +73,8 @@ class CommentElementTagProcessorTest {
|
||||||
</html>
|
</html>
|
||||||
""");
|
""");
|
||||||
|
|
||||||
when(componentsFinder.getExtensions(CommentWidget.class))
|
when(extensionGetter.getEnabledExtensionByDefinition(eq(CommentWidget.class)))
|
||||||
.thenReturn(List.of(new DefaultCommentWidget()));
|
.thenReturn(Flux.just(new DefaultCommentWidget()));
|
||||||
result = templateEngine.process("commentWidget", context);
|
result = templateEngine.process("commentWidget", context);
|
||||||
assertThat(result).isEqualTo("""
|
assertThat(result).isEqualTo("""
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
Loading…
Reference in New Issue