feat: delegate blog listing to BlogService
This commit is contained in:
parent
79a45643cb
commit
83e5757429
@ -1,16 +1,73 @@
|
|||||||
@page
|
@page
|
||||||
|
@using Humanizer
|
||||||
@using OliverBooth.Data.Blog
|
@using OliverBooth.Data.Blog
|
||||||
|
@using OliverBooth.Services
|
||||||
@model OliverBooth.Pages.Blog.Index
|
@model OliverBooth.Pages.Blog.Index
|
||||||
|
@inject BlogService BlogService
|
||||||
|
|
||||||
@foreach (BlogPost post in Model.BlogPosts)
|
@foreach (BlogPost post in BlogService.AllPosts)
|
||||||
{
|
{
|
||||||
<h2>
|
Author? author = Model.GetAuthor(post);
|
||||||
<a asp-page="/blog/article" asp-route-year="@post.Published.Year" asp-route-month="@post.Published.Month.ToString().PadLeft(2, '0')" asp-route-slug="@post.Slug">@post.Title</a>
|
DateTimeOffset published = post.Published;
|
||||||
</h2>
|
var year = published.ToString("yyyy");
|
||||||
<p class="text-muted">@post.Published.ToString("MMMM dd, yyyy") • @Model.GetAuthor(post)?.Name</p>
|
var month = published.ToString("MM");
|
||||||
<p>@Html.Raw(Model.SanitizeContent(Model.TrimContent(post.Body, out bool trimmed)))</p>
|
var day = published.ToString("dd");
|
||||||
if (trimmed)
|
|
||||||
{
|
bool isLegacyPost = post.WordPressId is not null;
|
||||||
<p><a asp-page="/blog/article" asp-route-year="@post.Published.Year" asp-route-month="@post.Published.Month.ToString().PadLeft(2, '0')" asp-route-slug="@post.Slug">Read more...</a></p>
|
string disqusDomain = isLegacyPost ? "https://blog.oliverbooth.dev" : "https://oliverbooth.dev/blog";
|
||||||
}
|
string disqusId = isLegacyPost ? $"{post.WordPressId} {disqusDomain}/?p={post.WordPressId}" : post.Id.ToString();
|
||||||
|
|
||||||
|
<div class="card blog-card" style="margin-bottom: 50px;">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2>
|
||||||
|
<a asp-page="/blog/article"
|
||||||
|
asp-route-year="@year"
|
||||||
|
asp-route-month="@month"
|
||||||
|
asp-route-day="@day"
|
||||||
|
asp-route-slug="@post.Slug">
|
||||||
|
@post.Title
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p class="text-muted">
|
||||||
|
<img class="blog-author-icon" src="https://gravatar.com/avatar/@author?.AvatarHash?s=28">
|
||||||
|
@author?.Name
|
||||||
|
•
|
||||||
|
<abbr data-bs-toggle="tooltip" data-bs-title="@post.Published.ToString("f")">
|
||||||
|
@post.Published.Humanize()
|
||||||
|
</abbr>
|
||||||
|
@if (post.EnableComments)
|
||||||
|
{
|
||||||
|
<span>•</span>
|
||||||
|
<a asp-page="/blog/article"
|
||||||
|
asp-route-year="@year"
|
||||||
|
asp-route-month="@month"
|
||||||
|
asp-route-day="@day"
|
||||||
|
asp-route-slug="@post.Slug"
|
||||||
|
asp-fragment="disqus_thread" data-disqus-identifier="@disqusId">
|
||||||
|
0 Comments
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>@Html.Raw(Model.SanitizeContent(Model.TrimContent(post.Body, out bool trimmed)))</p>
|
||||||
|
|
||||||
|
<article>
|
||||||
|
@if (trimmed)
|
||||||
|
{
|
||||||
|
<p>
|
||||||
|
<a asp-page="/blog/article"
|
||||||
|
asp-route-year="@year"
|
||||||
|
asp-route-month="@month"
|
||||||
|
asp-route-day="@day"
|
||||||
|
asp-route-slug="@post.Slug">
|
||||||
|
Read more...
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script id="dsq-count-scr" src="https://oliverbooth-dev.disqus.com/count.js" async></script>
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using Humanizer;
|
using Humanizer;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using OliverBooth.Data;
|
using OliverBooth.Data;
|
||||||
@ -19,7 +20,7 @@ public class Index : PageModel
|
|||||||
|
|
||||||
public string SanitizeContent(string content)
|
public string SanitizeContent(string content)
|
||||||
{
|
{
|
||||||
content = content.Replace("<more>", string.Empty);
|
content = content.Replace("<!--more-->", string.Empty);
|
||||||
|
|
||||||
while (content.Contains("\n\n"))
|
while (content.Contains("\n\n"))
|
||||||
{
|
{
|
||||||
@ -32,7 +33,7 @@ public class Index : PageModel
|
|||||||
public string TrimContent(string content, out bool trimmed)
|
public string TrimContent(string content, out bool trimmed)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<char> span = content.AsSpan();
|
ReadOnlySpan<char> span = content.AsSpan();
|
||||||
int moreIndex = span.IndexOf("<more>", StringComparison.Ordinal);
|
int moreIndex = span.IndexOf("<!--more-->", StringComparison.Ordinal);
|
||||||
trimmed = moreIndex != -1 || span.Length > 256;
|
trimmed = moreIndex != -1 || span.Length > 256;
|
||||||
return moreIndex != -1 ? span[..moreIndex].Trim().ToString() : content.Truncate(256);
|
return moreIndex != -1 ? span[..moreIndex].Trim().ToString() : content.Truncate(256);
|
||||||
}
|
}
|
||||||
@ -43,9 +44,22 @@ public class Index : PageModel
|
|||||||
return context.Authors.FirstOrDefault(a => a.Id == post.AuthorId);
|
return context.Authors.FirstOrDefault(a => a.Id == post.AuthorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnGet()
|
public IActionResult OnGet([FromQuery(Name = "p")] int? postId = null)
|
||||||
{
|
{
|
||||||
using BlogContext context = _dbContextFactory.CreateDbContext();
|
using BlogContext context = _dbContextFactory.CreateDbContext();
|
||||||
BlogPosts = context.BlogPosts.ToArray();
|
if (postId is null)
|
||||||
|
{
|
||||||
|
BlogPosts = context.BlogPosts.ToArray();
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
BlogPost? post = context.BlogPosts.FirstOrDefault(p => p.WordPressId == postId);
|
||||||
|
|
||||||
|
if (post is not null)
|
||||||
|
{
|
||||||
|
return Redirect($"/blog/{post.Published:yyyy/MM}/{post.Slug}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotFound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ builder.Services.AddSingleton(new MarkdownPipelineBuilder()
|
|||||||
|
|
||||||
builder.Services.AddDbContextFactory<BlogContext>();
|
builder.Services.AddDbContextFactory<BlogContext>();
|
||||||
builder.Services.AddDbContextFactory<WebContext>();
|
builder.Services.AddDbContextFactory<WebContext>();
|
||||||
|
builder.Services.AddSingleton<BlogService>();
|
||||||
builder.Services.AddRazorPages().AddRazorRuntimeCompilation();
|
builder.Services.AddRazorPages().AddRazorRuntimeCompilation();
|
||||||
builder.Services.AddControllersWithViews();
|
builder.Services.AddControllersWithViews();
|
||||||
builder.Services.AddRouting(options => options.LowercaseUrls = true);
|
builder.Services.AddRouting(options => options.LowercaseUrls = true);
|
||||||
|
32
OliverBooth/Services/BlogService.cs
Normal file
32
OliverBooth/Services/BlogService.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using OliverBooth.Data;
|
||||||
|
using OliverBooth.Data.Blog;
|
||||||
|
|
||||||
|
namespace OliverBooth.Services;
|
||||||
|
|
||||||
|
public sealed class BlogService
|
||||||
|
{
|
||||||
|
private IDbContextFactory<BlogContext> _dbContextFactory;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BlogService" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dbContextFactory">The <see cref="IDbContextFactory{TContext}" />.</param>
|
||||||
|
public BlogService(IDbContextFactory<BlogContext> dbContextFactory)
|
||||||
|
{
|
||||||
|
_dbContextFactory = dbContextFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a read-only view of all blog posts.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A read-only view of all blog posts.</returns>
|
||||||
|
public IReadOnlyCollection<BlogPost> AllPosts
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using BlogContext context = _dbContextFactory.CreateDbContext();
|
||||||
|
return context.BlogPosts.OrderByDescending(p => p.Published).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user