Skip to content

Commit 165595f

Browse files
committed
feat: Show Similiar blog posts
1 parent ce04058 commit 165595f

File tree

28 files changed

+512
-53
lines changed

28 files changed

+512
-53
lines changed

.editorconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ dotnet_diagnostic.S3875.severity = none # Remove this overload of 'operato
419419
dotnet_diagnostic.IDE0005.severity = none # IDE0005: Using directive is unnecessary
420420
dotnet_diagnostic.IDE0021.severity = suggestion # IDE0021: Use expression body for constructor
421421
dotnet_diagnostic.IDE0022.severity = suggestion # IDE0022: Use expression body for method
422+
dotnet_diagnostic.IDE0055.severity = none # IDE0055: Fix formatting
422423
dotnet_diagnostic.IDE0058.severity = none # IDE0058: Expression value is never used
423424
dotnet_diagnostic.IDE0079.severity = warning # IDE0079: Remove unnecessary suppression
424425
dotnet_diagnostic.IDE0290.severity = none # IDE0290: Use primary constructor
@@ -443,6 +444,7 @@ dotnet_diagnostic.CA1055.severity = none # CA1055: Uri return values should not
443444
dotnet_diagnostic.CA1056.severity = none # CA1056: Uri properties should not be strings
444445
dotnet_diagnostic.CA1812.severity = none # CA1812: Avoid uninstantiated internal classes
445446
dotnet_diagnostic.CA2201.severity = suggestion # CA2201: Do not raise reserved exception types
447+
dotnet_diagnostic.CA2227.severity = suggestion # CA2227: Collection properties should be read only
446448

447449
# SonarAnalyzer.CSharp
448450
# https://rules.sonarsource.com/csharp

LinkDotNet.Blog.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1919
ProjectSection(SolutionItems) = preProject
2020
Readme.md = Readme.md
2121
.editorconfig = .editorconfig
22+
MIGRATION.md = MIGRATION.md
2223
EndProjectSection
2324
EndProject
2425
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{86FD0EB5-13F9-4F1C-ADA1-072EEFEFF1E9}"

MIGRATION.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Migration Guide
2+
This document describes the changes that need to be made to migrate from one version of the blog to another.
3+
4+
## 8.0 to 9.0
5+
A new `SimilarBlogPost` table is introduced to store similar blog posts.
6+
7+
```sql
8+
CREATE TABLE SimilarBlogPosts
9+
(
10+
Id [NVARCHAR](450) NOT NULL,
11+
SimilarBlogPostIds NVARCHAR(1350) NOT NULL,
12+
)
13+
14+
ALTER TABLE SimilarBlogPosts
15+
ADD CONSTRAINT PK_SimilarBlogPosts PRIMARY KEY (Id)
16+
```
17+
18+
Add the following to the `appsettings.json`:
19+
20+
```json
21+
{
22+
"SimilarBlogPosts": true
23+
}
24+
```
25+
26+
Or `false` if you don't want to use this feature.

docs/Setup/Configuration.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ The appsettings.json file has a lot of options to customize the content of the b
4848
"KofiToken": "ABC123",
4949
"GithubSponsorName": "your-tag-here",
5050
"ShowReadingIndicator": true,
51-
"PatreonName": "your-tag-here"
51+
"PatreonName": "your-tag-here",
52+
"SimlarBlogPosts": "true"
5253
}
5354
```
5455

@@ -85,3 +86,4 @@ The appsettings.json file has a lot of options to customize the content of the b
8586
| GithubSponsorName | string | Enables the "Github Sponsor" button which redirects to GitHub. Only pass in the user name instead of the url. |
8687
| ShowReadingIndicator | boolean | If set to `true` (default) a circle indicates the progress when a user reads a blog post (without comments). |
8788
| PatreonName | string | Enables the "Become a patreon" button that redirects to patreon.com. Only pass the user name (public profile) as user name. |
89+
| SimilarBlogPosts | boolean | If set to `true` (default) similar blog posts are shown at the end of a blog post. |
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using System.Collections.Generic;
2+
3+
namespace LinkDotNet.Blog.Domain;
4+
5+
public class SimilarBlogPost : Entity
6+
{
7+
public IList<string> SimilarBlogPostIds { get; set; } = [];
8+
}

src/LinkDotNet.Blog.Infrastructure/Persistence/Sql/BlogDbContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public BlogDbContext(DbContextOptions options)
2424

2525
public DbSet<BlogPostRecord> BlogPostRecords { get; set; }
2626

27+
public DbSet<SimilarBlogPost> SimilarBlogPosts { get; set; }
28+
2729
protected override void OnModelCreating(ModelBuilder modelBuilder)
2830
{
2931
ArgumentNullException.ThrowIfNull(modelBuilder);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using LinkDotNet.Blog.Domain;
2+
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
4+
5+
namespace LinkDotNet.Blog.Infrastructure.Persistence.Sql.Mapping;
6+
7+
internal sealed class SimilarBlogPostConfiguration : IEntityTypeConfiguration<SimilarBlogPost>
8+
{
9+
public void Configure(EntityTypeBuilder<SimilarBlogPost> builder)
10+
{
11+
builder.HasKey(b => b.Id);
12+
builder.Property(b => b.Id)
13+
.IsUnicode(false)
14+
.ValueGeneratedOnAdd();
15+
builder.Property(b => b.SimilarBlogPostIds).HasMaxLength(450 * 3).IsRequired();
16+
}
17+
}

src/LinkDotNet.Blog.Web/ApplicationConfiguration.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public sealed record ApplicationConfiguration
1717
public bool IsAboutMeEnabled { get; set; }
1818

1919
public bool IsGiscusEnabled { get; set; }
20+
2021
public bool IsDisqusEnabled { get; set; }
2122

2223
public string KofiToken { get; init; }
@@ -32,4 +33,6 @@ public sealed record ApplicationConfiguration
3233
public string PatreonName { get; init; }
3334

3435
public bool IsPatreonEnabled => !string.IsNullOrEmpty(PatreonName);
36+
37+
public bool ShowSimilarPosts { get; init; }
3538
}

src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewBlogPost.razor

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
@using LinkDotNet.Blog.Domain
2+
@using NCronJob
23
@inject IJSRuntime JSRuntime
4+
@inject IInstantJobRegistry InstantJobRegistry
35

46
<div class="container">
57
<h3 class="fw-bold">@Title</h3>
@@ -119,6 +121,7 @@
119121
{
120122
canSubmit = false;
121123
await OnBlogPostCreated.InvokeAsync(model.ToBlogPost());
124+
InstantJobRegistry.RunInstantJob<SimilarBlogPostJob>(parameter: true);
122125
ClearModel();
123126
canSubmit = true;
124127
}

src/LinkDotNet.Blog.Web/Features/BlogPostPublisher.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,15 @@ public BlogPostPublisher(IRepository<BlogPost> repository, ICacheInvalidator cac
2525

2626
public async Task RunAsync(JobExecutionContext context, CancellationToken token)
2727
{
28+
ArgumentNullException.ThrowIfNull(context);
29+
2830
LogPublishStarting();
29-
await PublishScheduledBlogPostsAsync();
31+
var publishedPosts = await PublishScheduledBlogPostsAsync();
32+
context.Output = publishedPosts;
3033
LogPublishStopping();
3134
}
3235

33-
private async Task PublishScheduledBlogPostsAsync()
36+
private async Task<int> PublishScheduledBlogPostsAsync()
3437
{
3538
LogCheckingForScheduledBlogPosts();
3639

@@ -46,6 +49,8 @@ private async Task PublishScheduledBlogPostsAsync()
4649
{
4750
cacheInvalidator.Cancel();
4851
}
52+
53+
return blogPostsToPublish.Count;
4954
}
5055

5156
private async Task<IPagedList<BlogPost>> GetScheduledBlogPostsAsync()

0 commit comments

Comments
 (0)