Implemented RSS feed with Author filter
This commit is contained in:
parent
9f6f3cb142
commit
7cd24d29f7
|
@ -1,12 +1,22 @@
|
||||||
@page "/profile/{id:guid}"
|
@page "/profile/{id:guid}"
|
||||||
@using Wave.Data
|
@using Wave.Data
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
|
@using Microsoft.Extensions.Options
|
||||||
@using Wave.Utilities
|
@using Wave.Utilities
|
||||||
|
|
||||||
@inject IDbContextFactory<ApplicationDbContext> ContextFactory
|
@inject IDbContextFactory<ApplicationDbContext> ContextFactory
|
||||||
|
@inject IOptions<Customization> Customizations
|
||||||
|
@inject IOptions<Features> Features
|
||||||
@inject IStringLocalizer<UserView> Localizer
|
@inject IStringLocalizer<UserView> Localizer
|
||||||
@inject IMessageDisplay Message
|
@inject IMessageDisplay Message
|
||||||
|
|
||||||
|
<HeadContent>
|
||||||
|
@if (Features.Value.Rss && User is not null) {
|
||||||
|
<link rel="alternate" type="application/rss+xml" title="RSS Feed on @Customizations.Value.AppName | User @User.FullName" href="/rss/rss.xml?author=@User.Id">
|
||||||
|
<link rel="alternate" type="application/atom+xml" title="Atom RSS Feed on @Customizations.Value.AppName | User @User.FullName" href="/rss/atom.xml?author=@User.Id">
|
||||||
|
}
|
||||||
|
</HeadContent>
|
||||||
|
|
||||||
<PageTitle>@(TitlePrefix + @Localizer["Title"] + " | " + (User?.FullName ?? Localizer["NotFound_Title"]))</PageTitle>
|
<PageTitle>@(TitlePrefix + @Localizer["Title"] + " | " + (User?.FullName ?? Localizer["NotFound_Title"]))</PageTitle>
|
||||||
|
|
||||||
@if (User is null) {
|
@if (User is null) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.ServiceModel.Syndication;
|
using System.ServiceModel.Syndication;
|
||||||
|
using System.Web;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
@ -18,10 +19,10 @@ public class RssController(IOptions<Customization> customizations, ApplicationDb
|
||||||
[HttpGet("rss.xml", Name = "RssFeed")]
|
[HttpGet("rss.xml", Name = "RssFeed")]
|
||||||
[Produces("application/rss+xml")]
|
[Produces("application/rss+xml")]
|
||||||
[ResponseCache(Duration = 60*15, Location = ResponseCacheLocation.Any)]
|
[ResponseCache(Duration = 60*15, Location = ResponseCacheLocation.Any)]
|
||||||
public async Task<IActionResult> GetRssFeedAsync(string? category = null) {
|
public async Task<IActionResult> GetRssFeedAsync(string? category = null, Guid? author = null) {
|
||||||
if (!Features.Value.Rss) return new JsonResult("RSS is disabled") {StatusCode = StatusCodes.Status401Unauthorized};
|
if (!Features.Value.Rss) return new JsonResult("RSS is disabled") {StatusCode = StatusCodes.Status401Unauthorized};
|
||||||
|
|
||||||
var feed = await CreateFeedAll("RssFeed", category);
|
var feed = await CreateFeedAll("RssFeed", category, author);
|
||||||
if (feed is null) return NotFound();
|
if (feed is null) return NotFound();
|
||||||
Response.ContentType = "application/atom+xml";
|
Response.ContentType = "application/atom+xml";
|
||||||
return Ok(feed);
|
return Ok(feed);
|
||||||
|
@ -29,16 +30,16 @@ public class RssController(IOptions<Customization> customizations, ApplicationDb
|
||||||
[HttpGet("atom.xml", Name = "AtomFeed")]
|
[HttpGet("atom.xml", Name = "AtomFeed")]
|
||||||
[Produces("application/atom+xml")]
|
[Produces("application/atom+xml")]
|
||||||
[ResponseCache(Duration = 60*15, Location = ResponseCacheLocation.Any)]
|
[ResponseCache(Duration = 60*15, Location = ResponseCacheLocation.Any)]
|
||||||
public async Task<IActionResult> GetAtomFeedAsync(string? category = null) {
|
public async Task<IActionResult> GetAtomFeedAsync(string? category = null, Guid? author = null) {
|
||||||
if (!Features.Value.Rss) return new JsonResult("RSS is disabled") {StatusCode = StatusCodes.Status401Unauthorized};
|
if (!Features.Value.Rss) return new JsonResult("RSS is disabled") {StatusCode = StatusCodes.Status401Unauthorized};
|
||||||
|
|
||||||
var feed = await CreateFeedAll("AtomFeed", category);
|
var feed = await CreateFeedAll("AtomFeed", category, author);
|
||||||
if (feed is null) return NotFound();
|
if (feed is null) return NotFound();
|
||||||
Response.ContentType = "application/atom+xml";
|
Response.ContentType = "application/atom+xml";
|
||||||
return Ok(feed);
|
return Ok(feed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<SyndicationFeed?> CreateFeedAll(string? routeName, string? category) {
|
private async Task<SyndicationFeed?> CreateFeedAll(string? routeName, string? category, Guid? author) {
|
||||||
var now = DateTimeOffset.UtcNow;
|
var now = DateTimeOffset.UtcNow;
|
||||||
IQueryable<Article> query = Context.Set<Article>()
|
IQueryable<Article> query = Context.Set<Article>()
|
||||||
.Include(a => a.Author)
|
.Include(a => a.Author)
|
||||||
|
@ -49,16 +50,21 @@ public class RssController(IOptions<Customization> customizations, ApplicationDb
|
||||||
if (!string.IsNullOrWhiteSpace(category)) {
|
if (!string.IsNullOrWhiteSpace(category)) {
|
||||||
query = query.Where(a => a.Categories.Any(c => c.Name == category));
|
query = query.Where(a => a.Categories.Any(c => c.Name == category));
|
||||||
}
|
}
|
||||||
|
if (author is { } a1) {
|
||||||
|
string authorString = a1.ToString();
|
||||||
|
query = query.Where(a => a.Author.Id == authorString);
|
||||||
|
}
|
||||||
|
|
||||||
query = query.Take(15);
|
query = query.Take(15);
|
||||||
var articles = await query.ToListAsync();
|
var articles = await query.ToListAsync();
|
||||||
if (articles.Count < 1) return null;
|
if (articles.Count < 1) return null;
|
||||||
var date = query.Max(a => a.PublishDate);
|
var date = query.Max(a => a.PublishDate);
|
||||||
|
|
||||||
return CreateFeedAsync(articles, date, routeName, category);
|
return CreateFeedAsync(articles, date, routeName, category, author);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SyndicationFeed CreateFeedAsync(IEnumerable<Article> articles, DateTimeOffset date, string? routeName, string? category) {
|
private SyndicationFeed CreateFeedAsync(IEnumerable<Article> articles, DateTimeOffset date,
|
||||||
|
string? routeName, string? category, Guid? author) {
|
||||||
var customizations = Customizations.Value;
|
var customizations = Customizations.Value;
|
||||||
|
|
||||||
string appName = customizations.AppName;
|
string appName = customizations.AppName;
|
||||||
|
@ -68,17 +74,28 @@ public class RssController(IOptions<Customization> customizations, ApplicationDb
|
||||||
} else {
|
} else {
|
||||||
host = new Uri($"https://{Request.Host}", UriKind.Absolute);
|
host = new Uri($"https://{Request.Host}", UriKind.Absolute);
|
||||||
}
|
}
|
||||||
var feedLink = new Uri(Url.RouteUrl(routeName, null, "https", host.Host) ?? host.AbsoluteUri);
|
var feedLink = new UriBuilder(Url.RouteUrl(routeName, null, "https", host.Host) ?? host.AbsoluteUri);
|
||||||
var htmlLink = host;
|
var htmlLink = new UriBuilder(host);
|
||||||
if (category is not null) {
|
if (category is not null) {
|
||||||
feedLink = new Uri(feedLink.AbsoluteUri + "?category=" + WebUtility.HtmlEncode(category));
|
feedLink.Query = "category=" + WebUtility.HtmlEncode(category);
|
||||||
htmlLink = new Uri(host, "/category/" + WebUtility.HtmlEncode(category));
|
htmlLink.Path = "/category/" + WebUtility.HtmlEncode(category);
|
||||||
|
}
|
||||||
|
if (author is not null) {
|
||||||
|
var query = HttpUtility.ParseQueryString(feedLink.Query);
|
||||||
|
query.Add("author", author.ToString());
|
||||||
|
feedLink.Query = query.ToString();
|
||||||
|
|
||||||
|
if (htmlLink.Path.Length < 2) {
|
||||||
|
htmlLink.Path = "/profile/" + author;
|
||||||
|
} else {
|
||||||
|
htmlLink.Query = "?author=" + author;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var feed = new SyndicationFeed(appName, "Feed on " + appName, htmlLink, host.AbsoluteUri, date) {
|
var feed = new SyndicationFeed(appName, "Feed on " + appName, htmlLink.Uri, host.AbsoluteUri, date) {
|
||||||
TimeToLive = TimeSpan.FromMinutes(15),
|
TimeToLive = TimeSpan.FromMinutes(15),
|
||||||
Generator = "Wave",
|
Generator = "Wave",
|
||||||
Links = { new SyndicationLink(feedLink) {RelationshipType = "self"} },
|
Links = { new SyndicationLink(feedLink.Uri) {RelationshipType = "self"} },
|
||||||
Items = GetItems(articles, host)
|
Items = GetItems(articles, host)
|
||||||
};
|
};
|
||||||
if (category != null) feed.Categories.Add(new SyndicationCategory(category));
|
if (category != null) feed.Categories.Add(new SyndicationCategory(category));
|
||||||
|
|
Loading…
Reference in a new issue