CmsKit - Add UrlSlug to Blog

pull/7596/head
enisn 5 years ago
parent 4b23cb616a
commit 4290f3b932

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Validation; using Volo.Abp.Validation;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
@ -7,7 +8,12 @@ namespace Volo.CmsKit.Admin.Blogs
{ {
public class BlogDto : EntityDto<Guid> public class BlogDto : EntityDto<Guid>
{ {
[Required]
[DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))] [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))]
public string Name { get; set; } public string Name { get; set; }
[Required]
[DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxUrlSlugLength))]
public string UrlSlug { get; set; }
} }
} }

@ -3,5 +3,6 @@
public class BlogConsts public class BlogConsts
{ {
public static int MaxNameLength { get; set; } = 64; public static int MaxNameLength { get; set; } = 64;
public static int MaxUrlSlugLength { get; set; } = 64;
} }
} }

@ -8,6 +8,10 @@
<RootNamespace /> <RootNamespace />
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Unidecode.NET" Version="2.1.0" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Ddd.Domain\Volo.Abp.Ddd.Domain.csproj" /> <ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Ddd.Domain\Volo.Abp.Ddd.Domain.csproj" />
<ProjectReference Include="..\Volo.CmsKit.Domain.Shared\Volo.CmsKit.Domain.Shared.csproj" /> <ProjectReference Include="..\Volo.CmsKit.Domain.Shared\Volo.CmsKit.Domain.Shared.csproj" />

@ -3,6 +3,7 @@ using System;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.CmsKit.Blogs.Extensions;
namespace Volo.CmsKit.Blogs namespace Volo.CmsKit.Blogs
{ {
@ -11,19 +12,30 @@ namespace Volo.CmsKit.Blogs
public Blog( public Blog(
Guid id, Guid id,
[NotNull] string name, [NotNull] string name,
[NotNull] string urlSlug,
[CanBeNull] Guid? tenantId = null) : base(id) [CanBeNull] Guid? tenantId = null) : base(id)
{ {
SetName(name); SetName(name);
SetUrlSlug(urlSlug);
TenantId = tenantId; TenantId = tenantId;
} }
public string Name { get; protected set; } public string Name { get; protected set; }
public string UrlSlug { get; protected set; }
public Guid? TenantId { get; } public Guid? TenantId { get; }
public void SetName(string name) public void SetName(string name)
{ {
Name = Check.NotNullOrWhiteSpace(name, nameof(name), maxLength: BlogConsts.MaxNameLength); Name = Check.NotNullOrWhiteSpace(name, nameof(name), maxLength: BlogConsts.MaxNameLength);
} }
public void SetUrlSlug(string urlSlug)
{
Check.NotNullOrWhiteSpace(urlSlug, nameof(urlSlug), maxLength: BlogConsts.MaxNameLength);
UrlSlug = urlSlug.NormalizeAsUrlSlug();
}
} }
} }

@ -5,6 +5,7 @@ using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
using Volo.CmsKit.Blogs.Extensions;
using Volo.CmsKit.Users; using Volo.CmsKit.Users;
namespace Volo.CmsKit.Blogs namespace Volo.CmsKit.Blogs
@ -47,29 +48,7 @@ namespace Volo.CmsKit.Blogs
{ {
Check.NotNullOrWhiteSpace(urlSlug, nameof(urlSlug), BlogPostConsts.MaxUrlSlugLength, BlogPostConsts.MinUrlSlugLength); Check.NotNullOrWhiteSpace(urlSlug, nameof(urlSlug), BlogPostConsts.MaxUrlSlugLength, BlogPostConsts.MinUrlSlugLength);
UrlSlug = NormalizeUrlSlug(urlSlug); UrlSlug = urlSlug.NormalizeAsUrlSlug();
}
private string NormalizeUrlSlug(string value)
{
value = value.ToLowerInvariant();
// TODO: Find best way to unidecode.
// value = value.Unidecode();
// Replace spaces
value = Regex.Replace(value, @"\s", "-", RegexOptions.Compiled);
// Remove invalid chars
value = Regex.Replace(value, @"[^a-z0-9\s-_]", "", RegexOptions.Compiled);
// Trim dashes from end & dots
value = value.Trim('-', '_', '.');
// Replace double occurences of - or _
value = Regex.Replace(value, @"([-_]){2,}", "$1", RegexOptions.Compiled);
return value;
} }
} }
} }

@ -0,0 +1,30 @@
using System.Text.RegularExpressions;
using Unidecode.NET;
namespace Volo.CmsKit.Blogs.Extensions
{
public static class UrlSlugExtensions
{
public static string NormalizeAsUrlSlug(this string value)
{
value = value.ToLowerInvariant();
// Unidecode for non-latin characters
value = value.Unidecode();
// Replace spaces
value = Regex.Replace(value, @"\s", "-", RegexOptions.Compiled);
// Remove invalid chars
value = Regex.Replace(value, @"[^a-z0-9\s-_]", "", RegexOptions.Compiled);
// Trim dashes & dots
value = value.Trim('-', '_', '.');
// Replace double occurences of - or _
value = Regex.Replace(value, @"([-_]){2,}", "$1", RegexOptions.Compiled);
return value;
}
}
}

@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Volo.CmsKit.Blogs.Extensions;
using Shouldly;
namespace Volo.CmsKit.Blogs
{
public class UrlSlugExtensions_Tests
{
[Fact]
public void NormalizeAsUrlSlug_ShouldWorkProperly()
{
// Arrange
var name = "My awesome name";
var expected = "my-awesome-name";
// Act
var actual = name.NormalizeAsUrlSlug();
// Assert
actual.ShouldBe(expected);
}
[Fact]
public void NormalizeAsUrlSlug_ShouldWorkProperly_WithDot()
{
// Arrange
var name = "My Perfect Title v.2";
var expected = "my-perfect-title-v2";
// Act
var actual = name.NormalizeAsUrlSlug();
// Assert
actual.ShouldBe(expected);
}
[Fact]
public void NormalizeAsUrlSlug_ShouldWorkProperly_WithQuestionMark()
{
// Arrange
var name = "Are you gonna die?";
var expected = "are-you-gonna-die";
// Act
var actual = name.NormalizeAsUrlSlug();
// Assert
actual.ShouldBe(expected);
}
[Fact]
public void NormalizeAsUrlSlug_ShouldWorkProperly_WithAmpersand()
{
// Arrange
var name = "We & Machines Challenge";
var expected = "we-machines-challenge";
// Act
var actual = name.NormalizeAsUrlSlug();
// Assert
actual.ShouldBe(expected);
}
[Fact]
public void NormalizeAsUrlSlug_ShouldWorkProperly_WithDoubleDash()
{
// Arrange
var name = "Go and Code --part 2";
var expected = "go-and-code-part-2";
// Act
var actual = name.NormalizeAsUrlSlug();
// Assert
actual.ShouldBe(expected);
}
[Fact]
public void NormalizeAsUrlSlug_ShouldWorkProperly_WithCyrillicChars()
{
// Arrange
var name = "Мое классное название";
var expected = "moe-klassnoe-nazvanie";
// Act
var actual = name.NormalizeAsUrlSlug();
// Assert
actual.ShouldBe(expected);
}
[Fact]
public void NormalizeAsUrlSlug_ShouldWorkProperly_WithTurkishChars()
{
// Arrange
var name = "Özel Türkçe karakterler: ğüşiöç";
var expected = "ozel-turkce-karakterler-gusioc";
// Act
var actual = name.NormalizeAsUrlSlug();
// Assert
actual.ShouldBe(expected);
}
[Fact]
public void NormalizeAsUrlSlug_ShouldWorkProperly_WithChineseChars()
{
// Arrange
var name = "我的挑战";
var expected = "o-e-iao-han";
// Act
var actual = name.NormalizeAsUrlSlug();
// Assert
actual.ShouldBe(expected);
}
[Fact]
public void NormalizeAsUrlSlug_ShouldWorkProperly_WithEmoji()
{
// Arrange
var name = "Let's Rock 👊";
var expected = "lets-rock";
// Act
var actual = name.NormalizeAsUrlSlug();
// Assert
actual.ShouldBe(expected);
}
}
}

@ -308,7 +308,7 @@ namespace Volo.CmsKit
private async Task SeedBlogsAsync() private async Task SeedBlogsAsync()
{ {
var blog = await _blogRepository.InsertAsync(new Blog(_cmsKitTestData.Blog_Id, _cmsKitTestData.BlogName)); var blog = await _blogRepository.InsertAsync(new Blog(_cmsKitTestData.Blog_Id, _cmsKitTestData.BlogName, _cmsKitTestData.BlogUrlSlug));
await _blogPostRepository.InsertAsync(new BlogPost(_cmsKitTestData.BlogPost_1_Id, blog.Id, _cmsKitTestData.BlogPost_1_Title, _cmsKitTestData.BlogPost_1_UrlSlug, "Short desc 1")); await _blogPostRepository.InsertAsync(new BlogPost(_cmsKitTestData.BlogPost_1_Id, blog.Id, _cmsKitTestData.BlogPost_1_Title, _cmsKitTestData.BlogPost_1_UrlSlug, "Short desc 1"));

@ -77,6 +77,8 @@ namespace Volo.CmsKit
public string BlogName => "Cms Blog"; public string BlogName => "Cms Blog";
public string BlogUrlSlug => "cms-blog";
public Guid BlogPost_1_Id { get; } = Guid.NewGuid(); public Guid BlogPost_1_Id { get; } = Guid.NewGuid();
public string BlogPost_1_Title => "How to install CmsKit?"; public string BlogPost_1_Title => "How to install CmsKit?";

Loading…
Cancel
Save