Skip to content

Commit

Permalink
feat: add RSS feed for subscribing to post lists by tag slug (#43)
Browse files Browse the repository at this point in the history
### What this PR does?
支持根据标签别名订阅文章列表

示例: http://localhost:8090/feed/tags/halo.xml

Fixes #38

```release-note
支持根据标签别名订阅文章列表
```
  • Loading branch information
guqing authored Dec 5, 2024
1 parent 43c3955 commit 9a39c65
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
71 changes: 71 additions & 0 deletions app/src/main/java/run/halo/feed/provider/TagPostRssProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package run.halo.feed.provider;

import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import run.halo.app.content.PostContentService;
import run.halo.app.extension.ListResult;
import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.infra.ExternalLinkProcessor;
import run.halo.app.infra.ExternalUrlSupplier;
import run.halo.app.infra.SystemInfoGetter;
import run.halo.app.plugin.ReactiveSettingFetcher;
import run.halo.feed.BasicProp;
import run.halo.feed.RSS2;
import run.halo.feed.RssRouteItem;
import run.halo.feed.service.PostService;

@Component
public class TagPostRssProvider extends AbstractPostRssProvider implements RssRouteItem {

public TagPostRssProvider(PostService postService, ReactiveExtensionClient client,
ExternalLinkProcessor externalLinkProcessor, ReactiveSettingFetcher settingFetcher,
PostContentService postContentService, ExternalUrlSupplier externalUrlSupplier,
SystemInfoGetter systemInfoGetter) {
super(postService, client, externalLinkProcessor, settingFetcher, postContentService,
externalUrlSupplier, systemInfoGetter);
}

@Override
public Mono<String> pathPattern() {
return BasicProp.getBasicProp(settingFetcher)
.filter(BasicProp::isEnableCategories)
.map(prop -> "/tags/{slug}.xml");
}

@Override
@NonNull
public String displayName() {
return "标签文章订阅";
}

@Override
public String description() {
return "按标签订阅站点文章";
}

public Mono<RSS2> handler(ServerRequest request) {
var slug = request.pathVariable("slug");
return super.handler(request)
.flatMap(rss2 -> postService.getTagBySlug(slug)
.doOnNext(tag -> {
var displayName = tag.getSpec().getDisplayName();
var permalink = tag.getStatusOrDefault().getPermalink();
rss2.setTitle("标签:" + displayName + " - " + rss2.getTitle());
rss2.setLink(externalLinkProcessor.processLink(permalink));
})
.thenReturn(rss2)
);
}

@Override
protected Flux<PostWithContent> listPosts(ServerRequest request) {
var tagSlug = request.pathVariable("slug");
return listPostsByFunc(basicProp ->
postService.listPostByTagSlug(basicProp.getOutputNum(), tagSlug)
.flatMapIterable(ListResult::getItems)
);
}
}
5 changes: 5 additions & 0 deletions app/src/main/java/run/halo/feed/service/PostService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.content.Category;
import run.halo.app.core.extension.content.Post;
import run.halo.app.core.extension.content.Tag;
import run.halo.app.extension.ListResult;

public interface PostService {
Mono<ListResult<Post>> listPosts(int size);

Mono<ListResult<Post>> listPostByCategorySlug(int size, String categorySlug);

Mono<ListResult<Post>> listPostByTagSlug(int size, String tagSlug);

Mono<ListResult<Post>> listPostByAuthor(int size, String author);

Mono<Category> getCategoryBySlug(String categorySlug);

Mono<Tag> getTagBySlug(String slug);
}
22 changes: 22 additions & 0 deletions app/src/main/java/run/halo/feed/service/PostServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.content.Category;
import run.halo.app.core.extension.content.Post;
import run.halo.app.core.extension.content.Tag;
import run.halo.app.extension.ListOptions;
import run.halo.app.extension.ListResult;
import run.halo.app.extension.PageRequestImpl;
Expand Down Expand Up @@ -39,6 +40,17 @@ public Mono<ListResult<Post>> listPostByCategorySlug(int size, String categorySl
});
}

@Override
public Mono<ListResult<Post>> listPostByTagSlug(int size, String slug) {
return getTagBySlug(slug)
.flatMap(tag -> {
var tagName = tag.getMetadata().getName();
return client.listBy(Post.class,
buildPostListOptions(in("spec.tags", tagName)),
PageRequestImpl.ofSize(size).withSort(defaultSort()));
});
}

@Override
public Mono<ListResult<Post>> listPostByAuthor(int size, String author) {
return client.listBy(Post.class, buildPostListOptions(in("spec.owner", author)),
Expand All @@ -55,6 +67,16 @@ public Mono<Category> getCategoryBySlug(String categorySlug) {
.flatMap(listResult -> Mono.justOrEmpty(ListResult.first(listResult)));
}

@Override
public Mono<Tag> getTagBySlug(String slug) {
return client.listBy(Tag.class, ListOptions.builder()
.fieldQuery(equal("spec.slug", slug))
.build(),
PageRequestImpl.ofSize(1)
)
.flatMap(listResult -> Mono.justOrEmpty(ListResult.first(listResult)));
}

ListOptions buildPostListOptions() {
return buildPostListOptions(null);
}
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/resources/extensions/ext-definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ spec:
---
apiVersion: plugin.halo.run/v1alpha1
kind: ExtensionDefinition
metadata:
name: feed-tag-post-rss-item
spec:
className: run.halo.feed.provider.TagPostRssProvider
extensionPointName: feed-rss-route-item
displayName: "标签文章订阅"
description: "用于生成按照标签订阅文章列表的 RSS 订阅源"
---
apiVersion: plugin.halo.run/v1alpha1
kind: ExtensionDefinition
metadata:
name: feed-author-post-rss-item
spec:
Expand Down

0 comments on commit 9a39c65

Please sign in to comment.