Merge pull request #5 from StevanFreeborn/stevanfreeborn/feat/add-rss-feed
feat: add rss feed
This commit is contained in:
Vendored
+1
@@ -2,6 +2,7 @@
|
||||
"cSpell.words": [
|
||||
"Antiforgery",
|
||||
"blazor",
|
||||
"Entitize",
|
||||
"Hsts",
|
||||
"Markdig",
|
||||
"msedge"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Markdig" Version="0.36.2" />
|
||||
<PackageReference Include="System.ServiceModel.Syndication" Version="8.0.0" />
|
||||
<PackageReference Include="TestableIO.System.IO.Abstractions.Wrappers" Version="21.0.2" />
|
||||
<PackageReference Include="WebStoating.Markdig.Prism" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
global using System.IO.Abstractions;
|
||||
global using System.ServiceModel.Syndication;
|
||||
global using System.Text;
|
||||
global using System.Text.Json;
|
||||
global using System.Xml;
|
||||
global using System.Xml.Linq;
|
||||
|
||||
global using Blog.Components;
|
||||
global using Blog.Posts;
|
||||
|
||||
+63
-1
@@ -21,11 +21,73 @@ app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseAntiforgery();
|
||||
|
||||
app.UseStatusCodePagesWithRedirects("/Error/{0}");
|
||||
|
||||
app
|
||||
.MapGet("/rss", async (HttpContext context, IPostService postService) =>
|
||||
{
|
||||
var req = context.Request;
|
||||
var url = $"{req.Scheme}://{req.Host}{req.PathBase}";
|
||||
|
||||
var posts = await postService.GetPostsAsync();
|
||||
|
||||
var items = posts.Select(post =>
|
||||
{
|
||||
var uri = new Uri($"{url}/{post.Slug}");
|
||||
|
||||
var item = new SyndicationItem(
|
||||
post.Title,
|
||||
post.Lead,
|
||||
uri,
|
||||
post.Slug,
|
||||
post.PublishedAt
|
||||
);
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
var feed = new SyndicationFeed(
|
||||
"journal",
|
||||
"A blog by Stevan Freeborn",
|
||||
new Uri(url)
|
||||
)
|
||||
{
|
||||
Items = items,
|
||||
};
|
||||
|
||||
XNamespace atom = "http://www.w3.org/2005/Atom";
|
||||
feed.ElementExtensions.Add(
|
||||
new XElement(atom + "link",
|
||||
new XAttribute("href", url + "/rss"),
|
||||
new XAttribute("rel", "self"),
|
||||
new XAttribute("type", "application/rss+xml")
|
||||
)
|
||||
);
|
||||
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
Encoding = Encoding.UTF8,
|
||||
NewLineHandling = NewLineHandling.Entitize,
|
||||
Indent = true,
|
||||
Async = true,
|
||||
};
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
using var writer = XmlWriter.Create(stream, settings);
|
||||
|
||||
var rssFormatter = new Rss20FeedFormatter(feed, false);
|
||||
rssFormatter.WriteTo(writer);
|
||||
await writer.FlushAsync();
|
||||
|
||||
return Results.File(stream.ToArray(), "application/xml");
|
||||
})
|
||||
.WithDisplayName("RSS Feed")
|
||||
.WithDescription("RSS feed for the blog");
|
||||
|
||||
app
|
||||
.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
|
||||
app.UseStatusCodePagesWithRedirects("/Error/{0}");
|
||||
|
||||
app.Run();
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace Blog.Tests.EndToEnd;
|
||||
|
||||
[TestFixture]
|
||||
public class RssTests : BlogTest
|
||||
{
|
||||
[Test]
|
||||
public async Task Task_Rss_WhenFetched_ItShouldReturnRssFeed()
|
||||
{
|
||||
var response = await Page.APIRequest.GetAsync("/rss");
|
||||
response.Status.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
var xml = await response.BodyAsync();
|
||||
|
||||
var streamReader = new StreamReader(
|
||||
new MemoryStream(xml),
|
||||
Encoding.UTF8
|
||||
);
|
||||
|
||||
|
||||
var settings = new XmlReaderSettings
|
||||
{
|
||||
Async = true
|
||||
};
|
||||
|
||||
using var xmlReader = XmlReader.Create(streamReader, settings);
|
||||
var feed = SyndicationFeed.Load(xmlReader);
|
||||
|
||||
feed.Title.Text.Should().Be("journal");
|
||||
feed.Description.Text.Should().Be("A blog by Stevan Freeborn");
|
||||
feed.Items.Should().HaveCount(2);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
global using System.IO.Abstractions;
|
||||
global using System.Net;
|
||||
global using System.ServiceModel.Syndication;
|
||||
global using System.Text;
|
||||
global using System.Xml;
|
||||
|
||||
global using Blog.Posts;
|
||||
|
||||
@@ -10,10 +13,10 @@ global using Microsoft.AspNetCore.Hosting.Server;
|
||||
global using Microsoft.AspNetCore.Mvc.Testing;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Microsoft.Extensions.Hosting;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
global using Microsoft.Extensions.Options;
|
||||
global using Microsoft.Playwright;
|
||||
global using Microsoft.Playwright.NUnit;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
|
||||
global using Moq;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user