Skip to content

Commit

Permalink
refactor: extend RSS plugin to support feeds route
Browse files Browse the repository at this point in the history
  • Loading branch information
guqing committed Dec 10, 2024
1 parent 50d8826 commit a0203c7
Show file tree
Hide file tree
Showing 15 changed files with 365 additions and 169 deletions.
17 changes: 9 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
id "com.github.node-gradle.node" version "5.0.0"
id "io.freefair.lombok" version "8.0.0-rc2"
id "run.halo.plugin.devtools" version "0.1.1"
id "run.halo.plugin.devtools" version "0.4.1"
id 'java'
}

Expand All @@ -11,12 +11,14 @@ sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots' }
maven { url 'https://s01.oss.sonatype.org/content/repositories/release' }
maven { url 'https://s01.oss.sonatype.org/content/repositories/releases' }
}

dependencies {
implementation platform('run.halo.tools.platform:plugin:2.17.0-SNAPSHOT')
implementation platform('run.halo.tools.platform:plugin:2.20.11')
compileOnly 'run.halo.app:api'
compileOnly "run.halo.feed:api:1.4.0"

testImplementation 'run.halo.app:api'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down Expand Up @@ -46,21 +48,20 @@ build {
}

halo {
version = '2.17.0'
version = '2.20.11'
debug = true;
}


haloPlugin {
openApi {
outputDir = file("$rootDir/api-docs/openapi/v3_0")
groupingRules {
momentsApi {
displayName = 'Extension API for Moments Plugin'
pathsToMatch = [
'/apis/moment.halo.run/v1alpha1/**',
'/apis/console.api.moment.halo.run/v1alpha1/**',
'/apis/uc.api.moment.halo.run/v1alpha1/**'
'/apis/moment.halo.run/v1alpha1/**',
'/apis/console.api.moment.halo.run/v1alpha1/**',
'/apis/uc.api.moment.halo.run/v1alpha1/**'
]
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import run.halo.app.infra.utils.JsonUtils;
import run.halo.app.notification.NotificationReasonEmitter;
import run.halo.app.notification.UserIdentity;
import run.halo.moments.event.MomentHasNewCommentEvent;

/**
* Notification reason publisher for {@link Comment}.
Expand Down
1 change: 1 addition & 0 deletions src/main/java/run/halo/moments/CommentReconciler.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import run.halo.app.extension.controller.Controller;
import run.halo.app.extension.controller.ControllerBuilder;
import run.halo.app.extension.controller.Reconciler;
import run.halo.moments.event.MomentHasNewCommentEvent;

/**
* Reconciler for comment.
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/run/halo/moments/MomentReconciler.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.time.Instant;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import run.halo.app.core.extension.notification.Subscription;
import run.halo.app.extension.DefaultExtensionMatcher;
Expand All @@ -15,6 +16,8 @@
import run.halo.app.extension.controller.Reconciler;
import run.halo.app.extension.router.selector.FieldSelector;
import run.halo.app.notification.NotificationCenter;
import run.halo.moments.event.MomentDeletedEvent;
import run.halo.moments.event.MomentUpdatedEvent;

/**
* {@link Reconciler} for {@link Moment}.
Expand All @@ -29,13 +32,15 @@ public class MomentReconciler implements Reconciler<Reconciler.Request> {
private static final String FINALIZER = "moment-protection";
private final ExtensionClient client;
private final NotificationCenter notificationCenter;
private final ApplicationEventPublisher eventPublisher;

@Override
public Result reconcile(Request request) {
client.fetch(Moment.class, request.name()).ifPresent(moment -> {
if (ExtensionUtil.isDeleted(moment)) {
if (ExtensionUtil.removeFinalizers(moment.getMetadata(), Set.of(FINALIZER))) {
client.update(moment);
eventPublisher.publishEvent(new MomentDeletedEvent(this, request.name()));
}
return;
}
Expand All @@ -57,6 +62,8 @@ public Result reconcile(Request request) {
moment.getSpec().setApprovedTime(Instant.now());
}
client.update(moment);

eventPublisher.publishEvent(new MomentUpdatedEvent(this, request.name()));
});
return Result.doNotRetry();
}
Expand Down
66 changes: 0 additions & 66 deletions src/main/java/run/halo/moments/MomentRouter.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,23 @@
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static run.halo.app.theme.router.PageUrlUtils.totalPage;

import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import run.halo.app.extension.ConfigMap;
import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.infra.ExternalUrlSupplier;
import run.halo.app.infra.SystemSetting;
import run.halo.app.infra.utils.JsonUtils;
import run.halo.app.plugin.ReactiveSettingFetcher;
import run.halo.app.theme.router.PageUrlUtils;
import run.halo.app.theme.router.UrlContextListResult;
import run.halo.moments.finders.MomentFinder;
import run.halo.moments.util.RSS2;
import run.halo.moments.vo.MomentVo;


Expand All @@ -51,69 +42,12 @@ public class MomentRouter {

private final ReactiveSettingFetcher settingFetcher;

private final ReactiveExtensionClient client;

private final ExternalUrlSupplier externalUrlSupplier;

@Bean
RouterFunction<ServerResponse> momentRouterFunction() {
return route(GET("/moments").or(GET("/moments/page/{page:\\d+}")), handlerFunction())
.andRoute(GET("/moments/rss.xml"), handlerRss())
.andRoute(GET("/moments/{momentName:\\S+}"), handlerMomentDefault());
}

private HandlerFunction<ServerResponse> handlerRss() {
return request -> ServerResponse.ok()
.contentType(MediaType.TEXT_XML)
.body(buildRss(request), String.class);
}

private Mono<String> buildRss(ServerRequest request) {
var externalUrl = externalUrlSupplier.get();
if (!externalUrl.isAbsolute()) {
externalUrl = request.exchange().getRequest().getURI().resolve(externalUrl);
}

final var hostAddress = externalUrl;
return getSystemBasicSetting()
.flatMap(basicSetting -> getMomentTitle()
.map(momentTitle -> RSS2.builder()
.title(StringUtils.defaultString(basicSetting.getTitle()) + momentTitle)
.link(StringUtils.removeEnd(hostAddress.toString(), "/"))
.description(StringUtils.defaultString(basicSetting.getSubtitle()))
)
)
.flatMap(builder -> momentFinder.listAll()
.map(momentVo -> RSS2.Item.builder()
.title(momentVo.getOwner().getDisplayName() + " published on "
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault())
.format(momentVo.getSpec().getReleaseTime()))
.link(hostAddress.resolve("moments/" + momentVo.getMetadata().getName())
.toString())
.guid(hostAddress.resolve("moments/" + momentVo.getMetadata().getName())
.toString())
.description("""
<![CDATA[%s]]>
""".formatted(momentVo.getSpec().getContent().getHtml()))
.pubDate(momentVo.getSpec().getReleaseTime()).build())
.collectList()
.map(builder::items)
)
.map(RSS2.RSS2Builder::build)
.map(RSS2::toXmlString);
}

private Mono<SystemSetting.Basic> getSystemBasicSetting() {
return client.get(ConfigMap.class, SystemSetting.SYSTEM_CONFIG)
.mapNotNull(ConfigMap::getData)
.map(map -> {
String basicSetting = map.getOrDefault(SystemSetting.Basic.GROUP, "{}");
return JsonUtils.jsonToObject(basicSetting, SystemSetting.Basic.class);
});
}


private HandlerFunction<ServerResponse> handlerMomentDefault() {
return request -> {
String momentName = request.pathVariable("momentName");
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/run/halo/moments/event/MomentDeletedEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package run.halo.moments.event;

import lombok.Getter;
import org.springframework.context.ApplicationEvent;

@Getter
public class MomentDeletedEvent extends ApplicationEvent {
private final String momentName;

public MomentDeletedEvent(Object source, String momentName) {
super(source);
this.momentName = momentName;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package run.halo.moments;
package run.halo.moments.event;

import lombok.Getter;
import org.springframework.context.ApplicationEvent;
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/run/halo/moments/event/MomentUpdatedEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package run.halo.moments.event;

import lombok.Getter;
import org.springframework.context.ApplicationEvent;

@Getter
public class MomentUpdatedEvent extends ApplicationEvent {
private final String momentName;

public MomentUpdatedEvent(Object source, String momentName) {
super(source);
this.momentName = momentName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.Counter;
import run.halo.app.core.extension.User;
import run.halo.app.extension.ExtensionUtil;
import run.halo.app.extension.ListOptions;
import run.halo.app.extension.ListResult;
import run.halo.app.extension.PageRequest;
Expand Down Expand Up @@ -59,7 +60,7 @@ public Flux<MomentVo> listAll() {
listOptions.setFieldSelector(
FieldSelector.of(FIXED_QUERY));
return client.listAll(Moment.class, listOptions, defaultSort())
.flatMap(this::getMomentVo);
.concatMap(this::getMomentVo);
}

@Override
Expand All @@ -69,7 +70,8 @@ public Mono<ListResult<MomentVo>> list(Integer page, Integer size) {
}

static Sort defaultSort() {
return Sort.by("spec.releaseTime").descending();
return Sort.by("spec.releaseTime").descending()
.and(ExtensionUtil.defaultSort());
}

@Override
Expand All @@ -78,7 +80,7 @@ public Flux<MomentVo> listBy(String tag) {
var query = and(FIXED_QUERY, equal("spec.tags", tag));
listOptions.setFieldSelector(FieldSelector.of(query));
return client.listAll(Moment.class, listOptions, defaultSort())
.flatMap(this::getMomentVo);
.concatMap(this::getMomentVo);
}

@Override
Expand All @@ -104,7 +106,7 @@ public Flux<MomentTagVo> listAllTags() {
.toList();
})
.groupBy(MomentTagPair::tagName)
.flatMap(groupedFlux -> groupedFlux.count()
.concatMap(groupedFlux -> groupedFlux.count()
.defaultIfEmpty(0L)
.map(count -> MomentTagVo.builder()
.name(groupedFlux.key())
Expand Down
Loading

0 comments on commit a0203c7

Please sign in to comment.