refactor(blog): use api controller for /blog/feed endpoint
This commit is contained in:
parent
369436ccce
commit
bbc76bc305
|
@ -1,32 +1,39 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Xml.Serialization;
|
||||||
using System.Xml.Serialization;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using OliverBooth.Data.Blog;
|
using OliverBooth.Data.Blog;
|
||||||
using OliverBooth.Data.Blog.Rss;
|
using OliverBooth.Data.Blog.Rss;
|
||||||
using OliverBooth.Services;
|
using OliverBooth.Services;
|
||||||
|
|
||||||
namespace OliverBooth.Middleware;
|
namespace OliverBooth.Controllers.Blog;
|
||||||
|
|
||||||
internal sealed class RssMiddleware
|
[ApiController]
|
||||||
|
[Route("blog/feed")]
|
||||||
|
public class RssController : Controller
|
||||||
{
|
{
|
||||||
private readonly IBlogPostService _blogPostService;
|
private readonly IBlogPostService _blogPostService;
|
||||||
|
|
||||||
public RssMiddleware(RequestDelegate _, IBlogPostService blogPostService)
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RssController" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="blogPostService">The <see cref="IBlogPostService" />.</param>
|
||||||
|
public RssController(IBlogPostService blogPostService)
|
||||||
{
|
{
|
||||||
_blogPostService = blogPostService;
|
_blogPostService = blogPostService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Middleware")]
|
[HttpGet]
|
||||||
public async Task Invoke(HttpContext context)
|
[Produces("application/rss+xml")]
|
||||||
|
public IActionResult OnGet()
|
||||||
{
|
{
|
||||||
context.Response.ContentType = "application/rss+xml";
|
Response.ContentType = "application/rss+xml";
|
||||||
|
|
||||||
var baseUrl = $"https://{context.Request.Host}/blog";
|
var baseUrl = $"https://{Request.Host}/blog";
|
||||||
var blogItems = new List<BlogItem>();
|
var blogItems = new List<BlogItem>();
|
||||||
|
|
||||||
foreach (IBlogPost post in _blogPostService.GetAllBlogPosts())
|
foreach (IBlogPost post in _blogPostService.GetAllBlogPosts())
|
||||||
{
|
{
|
||||||
var url = $"{baseUrl}/{post.Published:yyyy/MM/dd}/{post.Slug}";
|
var url = $"{baseUrl}/{post.Published:yyyy/MM/dd}/{post.Slug}";
|
||||||
string excerpt = _blogPostService.RenderExcerpt(post, out _);
|
string excerpt = _blogPostService.RenderPost(post);
|
||||||
var description = $"{excerpt}<p><a href=\"{url}\">Read more...</a></p>";
|
var description = $"{excerpt}<p><a href=\"{url}\">Read more...</a></p>";
|
||||||
|
|
||||||
var item = new BlogItem
|
var item = new BlogItem
|
||||||
|
@ -36,7 +43,7 @@ internal sealed class RssMiddleware
|
||||||
Comments = $"{url}#disqus_thread",
|
Comments = $"{url}#disqus_thread",
|
||||||
Creator = post.Author.DisplayName,
|
Creator = post.Author.DisplayName,
|
||||||
PubDate = post.Published.ToString("R"),
|
PubDate = post.Published.ToString("R"),
|
||||||
Guid = $"{baseUrl}?pid={post.Id}",
|
Guid = post.WordPressId.HasValue ? $"{baseUrl}?p={post.WordPressId.Value}" : $"{baseUrl}?pid={post.Id}",
|
||||||
Description = description
|
Description = description
|
||||||
};
|
};
|
||||||
blogItems.Add(item);
|
blogItems.Add(item);
|
||||||
|
@ -68,7 +75,9 @@ internal sealed class RssMiddleware
|
||||||
xmlNamespaces.Add("sy", "http://purl.org/rss/1.0/modules/syndication/");
|
xmlNamespaces.Add("sy", "http://purl.org/rss/1.0/modules/syndication/");
|
||||||
xmlNamespaces.Add("slash", "http://purl.org/rss/1.0/modules/slash/");
|
xmlNamespaces.Add("slash", "http://purl.org/rss/1.0/modules/slash/");
|
||||||
|
|
||||||
await using var writer = new StreamWriter(context.Response.BodyWriter.AsStream());
|
using var writer = new StreamWriter(Response.BodyWriter.AsStream());
|
||||||
serializer.Serialize(writer, rss, xmlNamespaces);
|
serializer.Serialize(writer, rss, xmlNamespaces);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,6 +37,9 @@ internal sealed class BlogPost : IBlogPost
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public DateTimeOffset? Updated { get; internal set; }
|
public DateTimeOffset? Updated { get; internal set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int? WordPressId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the ID of the author of this blog post.
|
/// Gets or sets the ID of the author of this blog post.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -61,12 +64,6 @@ internal sealed class BlogPost : IBlogPost
|
||||||
/// <value>The Disqus URL path.</value>
|
/// <value>The Disqus URL path.</value>
|
||||||
internal string? DisqusPath { get; set; }
|
internal string? DisqusPath { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the WordPress ID of this blog post.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The WordPress ID of this blog post.</value>
|
|
||||||
internal int? WordPressId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Disqus domain for the blog post.
|
/// Gets the Disqus domain for the blog post.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -69,6 +69,14 @@ public interface IBlogPost
|
||||||
/// <value>The update date and time, or <see langword="null" /> if the post has not been updated.</value>
|
/// <value>The update date and time, or <see langword="null" /> if the post has not been updated.</value>
|
||||||
DateTimeOffset? Updated { get; }
|
DateTimeOffset? Updated { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the WordPress ID of the post.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The WordPress ID of the post, or <see langword="null" /> if the post was not imported from WordPress.
|
||||||
|
/// </value>
|
||||||
|
int? WordPressId { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Disqus identifier for the post.
|
/// Gets the Disqus identifier for the post.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
namespace OliverBooth.Middleware;
|
|
||||||
|
|
||||||
internal static class RssEndpointExtensions
|
|
||||||
{
|
|
||||||
public static IEndpointConventionBuilder MapRssFeed(this IEndpointRouteBuilder endpoints, string pattern)
|
|
||||||
{
|
|
||||||
RequestDelegate pipeline = endpoints.CreateApplicationBuilder()
|
|
||||||
.UseMiddleware<RssMiddleware>()
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
return endpoints.Map(pattern, pipeline).WithDisplayName("RSS Feed");
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue