Skip to content

Commit

Permalink
refactor: Moved reading time into BlogPost (#263)
Browse files Browse the repository at this point in the history
* refactor: Moved reading time into BlogPost

* Smaller refactoring

* refactor: Remove ref for out

* refactoring: Slug generation
  • Loading branch information
linkdotnet authored Dec 16, 2023
1 parent 90e0d8d commit d23a6b6
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 49 deletions.
39 changes: 21 additions & 18 deletions src/LinkDotNet.Blog.Domain/BlogPost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,34 +38,35 @@ private BlogPost()

public string TagsAsString => Tags is null ? string.Empty : string.Join(", ", Tags);

public int ReadingTimeInMinutes { get; private set; }

public string Slug => GenerateSlug();

private string GenerateSlug()
{
// Remove all accents and make the string lower case.
if (string.IsNullOrWhiteSpace(Title))
{
return Title;
}

Title = Title.Normalize(NormalizationForm.FormD);
var chars = Title
.Where(c => CharUnicodeInfo.GetUnicodeCategory(c)
!= UnicodeCategory.NonSpacingMark)
.ToArray();

Title = new string(chars).Normalize(NormalizationForm.FormC);

var slug = Title.ToLower(CultureInfo.CurrentCulture);
var normalizedTitle = Title.Normalize(NormalizationForm.FormD);
var stringBuilder = new StringBuilder();

// Remove all special characters from the string.
slug = MatchIfSpecialCharactersExist().Replace(slug, "");
foreach (var c in normalizedTitle.Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark))
{
stringBuilder.Append(c);
}

// Remove all additional spaces in favour of just one.
slug= MatchIfAdditionalSpacesExist().Replace(slug," ").Trim();
var cleanTitle = stringBuilder
.ToString()
.Normalize(NormalizationForm.FormC)
.ToLower(CultureInfo.CurrentCulture);

// Replace all spaces with the hyphen.
slug= MatchIfSpaceExist().Replace(slug, "-");
cleanTitle = MatchIfSpecialCharactersExist().Replace(cleanTitle, "");
cleanTitle = MatchIfAdditionalSpacesExist().Replace(cleanTitle, " ");
cleanTitle = MatchIfSpaceExist().Replace(cleanTitle, "-");

return slug;
return cleanTitle.Trim();
}

[GeneratedRegex(
Expand Down Expand Up @@ -114,7 +115,8 @@ public static BlogPost Create(
PreviewImageUrl = previewImageUrl,
PreviewImageUrlFallback = previewImageUrlFallback,
IsPublished = isPublished,
Tags = tags?.Select(t => t.Trim()).ToImmutableArray(),
Tags = tags?.Select(t => t.Trim()).ToImmutableArray() ?? ImmutableArray<string>.Empty,
ReadingTimeInMinutes = ReadingTimeCalculator.CalculateReadingTime(content),
};

return blogPost;
Expand Down Expand Up @@ -144,5 +146,6 @@ public void Update(BlogPost from)
PreviewImageUrlFallback = from.PreviewImageUrlFallback;
IsPublished = from.IsPublished;
Tags = from.Tags;
ReadingTimeInMinutes = from.ReadingTimeInMinutes;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Text.RegularExpressions;

namespace LinkDotNet.Blog.Web.Features.Services;
namespace LinkDotNet.Blog.Domain;

public static partial class ReadingTimeCalculator
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,65 +23,65 @@ public sealed class CreateNewModel
public string Title
{
get => title;
set => SetProperty(ref title, value);
set => SetProperty(out title, value);
}

[Required]
public string ShortDescription
{
get => shortDescription;
set => SetProperty(ref shortDescription, value);
set => SetProperty(out shortDescription, value);
}

[Required]
public string Content
{
get => content;
set => SetProperty(ref content, value);
set => SetProperty(out content, value);
}

[Required]
[MaxLength(1024)]
public string PreviewImageUrl
{
get => previewImageUrl;
set => SetProperty(ref previewImageUrl, value);
set => SetProperty(out previewImageUrl, value);
}

[Required]
[PublishedWithScheduledDateValidation]
public bool IsPublished
{
get => isPublished;
set => SetProperty(ref isPublished, value);
set => SetProperty(out isPublished, value);
}

[Required]
public bool ShouldUpdateDate
{
get => shouldUpdateDate;
set => SetProperty(ref shouldUpdateDate, value);
set => SetProperty(out shouldUpdateDate, value);
}

[FutureDateValidation]
public DateTime? ScheduledPublishDate
{
get => scheduledPublishDate;
set => SetProperty(ref scheduledPublishDate, value);
set => SetProperty(out scheduledPublishDate, value);
}

public string Tags
{
get => tags;
set => SetProperty(ref tags, value);
set => SetProperty(out tags, value);
}

[MaxLength(256)]
[FallbackUrlValidation]
public string PreviewImageUrlFallback
{
get => previewImageUrlFallback;
set => SetProperty(ref previewImageUrlFallback, value);
set => SetProperty(out previewImageUrlFallback, value);
}

public bool IsDirty { get; private set; }
Expand All @@ -108,7 +108,9 @@ public static CreateNewModel FromBlogPost(BlogPost blogPost)

public BlogPost ToBlogPost()
{
var tagList = string.IsNullOrWhiteSpace(Tags) ? ArraySegment<string>.Empty : Tags.Split(",");
var tagList = string.IsNullOrWhiteSpace(Tags)
? Array.Empty<string>()
: Tags.Split(",", StringSplitOptions.RemoveEmptyEntries);
DateTime? updatedDate = ShouldUpdateDate || originalUpdatedDate == default
? null
: originalUpdatedDate;
Expand All @@ -127,7 +129,7 @@ public BlogPost ToBlogPost()
return blogPost;
}

private void SetProperty<T>(ref T backingField, T value)
private void SetProperty<T>(out T backingField, T value)
{
backingField = value;
IsDirty = true;
Expand Down
17 changes: 2 additions & 15 deletions src/LinkDotNet.Blog.Web/Features/Components/ShortBlogPost.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
@using LinkDotNet.Blog.Web.Features.Services
@using Microsoft.Extensions.Caching.Memory

@inject IMemoryCache MemoryCache
<article>
<div class="blog-card @AltCssClass">
<div class="meta">
Expand All @@ -24,7 +23,7 @@
<li class="draft">Draft</li>
}
<li class="date me-4"><span>@BlogPost.UpdatedDate.ToString("dd/MM/yyyy")</span></li>
@if (BlogPost.Tags != null && BlogPost.Tags.Any())
@if (BlogPost.Tags.Any())
{
<li class="tags me-4">
<ul>
Expand All @@ -35,7 +34,7 @@
</ul>
</li>
}
<li class="read-time me-4">@readingTime min</li>
<li class="read-time me-4">@BlogPost.ReadingTimeInMinutes min</li>
</ul>
</div>
<div class="description">
Expand All @@ -50,8 +49,6 @@
</article>

@code {
private int readingTime;

[Parameter]
public BlogPost BlogPost { get; set; }

Expand Down Expand Up @@ -83,14 +80,4 @@

return base.SetParametersAsync(ParameterView.Empty);
}

protected override void OnInitialized()
{
var key = "reading-time-" + BlogPost.Id;
readingTime = MemoryCache.GetOrCreate(key, entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
return ReadingTimeCalculator.CalculateReadingTime(BlogPost.Content);
});
}
}
5 changes: 3 additions & 2 deletions tests/LinkDotNet.Blog.UnitTests/Domain/BlogPostTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ public void ShouldUpdateBlogPost()
{
var blogPostToUpdate = new BlogPostBuilder().Build();
blogPostToUpdate.Id = "random-id";
var blogPost = BlogPost.Create("Title", "Desc", "Content", "Url", true, previewImageUrlFallback: "Url2");
var blogPost = BlogPost.Create("Title", "Desc", "Other Content", "Url", true, previewImageUrlFallback: "Url2");
blogPost.Id = "something else";

blogPostToUpdate.Update(blogPost);

blogPostToUpdate.Title.Should().Be("Title");
blogPostToUpdate.ShortDescription.Should().Be("Desc");
blogPostToUpdate.Content.Should().Be("Content");
blogPostToUpdate.Content.Should().Be("Other Content");
blogPostToUpdate.PreviewImageUrl.Should().Be("Url");
blogPostToUpdate.PreviewImageUrlFallback.Should().Be("Url2");
blogPostToUpdate.IsPublished.Should().BeTrue();
blogPostToUpdate.Tags.Should().BeNullOrEmpty();
blogPostToUpdate.Slug.Should().NotBeNull();
blogPostToUpdate.ReadingTimeInMinutes.Should().Be(1);
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Linq;
using LinkDotNet.Blog.Web.Features.Services;
using LinkDotNet.Blog.Domain;

namespace LinkDotNet.Blog.UnitTests.Web.Features.Services;
namespace LinkDotNet.Blog.UnitTests.Domain;

public class ReadingTimeCalculatorTests
{
Expand Down

0 comments on commit d23a6b6

Please sign in to comment.