diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs index 823efdfc4e..2c3ff84d48 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs @@ -5,16 +5,10 @@ namespace Volo.CmsKit.Admin.Blogs { public class BlogPostDto : EntityDto { - public Guid BlogId { get; protected set; } + public Guid BlogId { get; set; } - public string Title { get; protected set; } + public string Title { get; set; } - public string UrlSlug { get; protected set; } - - public string CoverImageUrl { get; set; } - - public bool IsPublished { get; protected set; } - - public DateTime? PublishDate { get; protected set; } + public string UrlSlug { get; set; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateUpdateBlogPostDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateUpdateBlogPostDto.cs index b013a9d397..09d881189b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateUpdateBlogPostDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateUpdateBlogPostDto.cs @@ -4,12 +4,12 @@ namespace Volo.CmsKit.Admin.Blogs { public class CreateUpdateBlogPostDto { - public Guid BlogId { get; protected set; } + public Guid BlogId { get; set; } - public string Title { get; protected set; } + public string Title { get; set; } - public string UrlSlug { get; protected set; } + public string UrlSlug { get; set; } - public string CoverImageUrl { get; set; } + public string ShortDescription { get; set; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs index c714c6482b..36ded2ba1f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs @@ -1,8 +1,5 @@ using Microsoft.AspNetCore.Authorization; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; @@ -34,10 +31,12 @@ namespace Volo.CmsKit.Admin.Blogs public BlogPostAdminAppService( IRepository repository, IBlogPostManager blogPostManager, - IBlogPostRepository blogPostRepository) : base(repository) + IBlogPostRepository blogPostRepository, + IBlobContainer blobContainer) : base(repository) { BlogPostManager = blogPostManager; BlogPostRepository = blogPostRepository; + BlobContainer = blobContainer; GetListPolicyName = CmsKitAdminPermissions.BlogPosts.Default; GetPolicyName = CmsKitAdminPermissions.BlogPosts.Default; @@ -63,7 +62,7 @@ namespace Volo.CmsKit.Admin.Blogs input.BlogId, input.Title, input.UrlSlug, - input.CoverImageUrl)); + input.ShortDescription)); return MapToGetOutputDto(entity); } @@ -78,6 +77,8 @@ namespace Volo.CmsKit.Admin.Blogs MapToEntity(input, entity); + await BlogPostManager.UpdateAsync(entity); + return MapToGetOutputDto(entity); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs index 1524fe6299..e682e80d30 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs @@ -1,6 +1,8 @@ using AutoMapper; +using Volo.CmsKit.Admin.Blogs; using Volo.CmsKit.Admin.Contents; using Volo.CmsKit.Admin.Pages; +using Volo.CmsKit.Blogs; using Volo.CmsKit.Contents; using Volo.CmsKit.Pages; @@ -16,6 +18,12 @@ namespace Volo.CmsKit.Admin CreateMap(MemberList.Destination); CreateMap(MemberList.Source); CreateMap(MemberList.Source); + + CreateMap(MemberList.Destination); + CreateMap(MemberList.Source); + + CreateMap(MemberList.Destination) + .ReverseMap(); } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs index a4388aa945..607effcebd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs @@ -2,10 +2,12 @@ { public static class BlogPostConsts { - public static int MaxTitleLength { get; set; } = 256; + public static int MaxTitleLength { get; set; } = 64; public static int MaxUrlSlugLength { get; set; } = 256; public static int MinUrlSlugLength { get; set; } = 2; + + public static int MaxShortDescriptionLength { get; set; } = 256; } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs index 9ae19ff512..0ec587f52e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs @@ -9,8 +9,9 @@ namespace Volo.CmsKit.Blogs public class Blog : FullAuditedAggregateRoot, IMultiTenant { public Blog( + Guid id, [NotNull] string name, - [CanBeNull] Guid? tenantId = null) + [CanBeNull] Guid? tenantId = null) : base(id) { SetName(name); TenantId = tenantId; diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs index ac41adbe2a..62a73ec352 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs @@ -15,10 +15,10 @@ namespace Volo.CmsKit.Blogs public string Title { get; protected set; } - public string ShortDescription { get; set; } - public string UrlSlug { get; protected set; } + public string ShortDescription { get; set; } + public Guid? TenantId { get; } protected BlogPost() diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs index 2b139fbdb6..6bbb772072 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs @@ -9,33 +9,46 @@ namespace Volo.CmsKit.Blogs { public class BlogPostManager : DomainService, IBlogPostManager { - protected readonly IBlogPostRepository _blogPostRepository; + protected readonly IBlogPostRepository blogPostRepository; + protected readonly IBlogRepository blogRepository; - public BlogPostManager(IBlogPostRepository blogPostRepository) + public BlogPostManager( + IBlogPostRepository blogPostRepository, + IBlogRepository blogRepository) { - _blogPostRepository = blogPostRepository; + this.blogPostRepository = blogPostRepository; + this.blogRepository = blogRepository; } public async Task CreateAsync(BlogPost blogPost) { + await CheckBlogExistenceAsync(blogPost.BlogId); + await CheckUrlSlugExistenceAsync(blogPost.UrlSlug); - return await _blogPostRepository.InsertAsync(blogPost); + return await blogPostRepository.InsertAsync(blogPost); } public async Task UpdateAsync(BlogPost blogPost) { + await CheckBlogExistenceAsync(blogPost.BlogId); + await CheckUrlSlugExistenceAsync(blogPost.UrlSlug); - await _blogPostRepository.UpdateAsync(blogPost); + await blogPostRepository.UpdateAsync(blogPost); } private async Task CheckUrlSlugExistenceAsync(string urlSlug) { - if (await _blogPostRepository.SlugExistsAsync(urlSlug)) + if (await blogPostRepository.SlugExistsAsync(urlSlug)) { throw new BlogPostUrlSlugAlreadyExistException(urlSlug); } } + + private async Task CheckBlogExistenceAsync(Guid blogId) + { + await blogRepository.GetAsync(blogId); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostUrlSlugAlreadyExistException.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostUrlSlugAlreadyExistException.cs index 22816c5d7e..c21ccfa8e7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostUrlSlugAlreadyExistException.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostUrlSlugAlreadyExistException.cs @@ -19,9 +19,13 @@ namespace Volo.CmsKit.Blogs public BlogPostUrlSlugAlreadyExistException(string urlSlug) { + UrlSlug = urlSlug; + Code = CmsKitErrorCodes.Blogs.UrlSlugAlreadyExist; - WithData(nameof(BlogPost.UrlSlug), urlSlug); + WithData(nameof(UrlSlug), UrlSlug); } + + public string UrlSlug { get; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs index 3322253205..c868bde907 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs @@ -229,6 +229,8 @@ namespace Volo.CmsKit.EntityFrameworkCore b.Property(p => p.UrlSlug).IsRequired().HasMaxLength(BlogPostConsts.MaxUrlSlugLength); + b.Property(p => p.ShortDescription).HasMaxLength(BlogPostConsts.MaxShortDescriptionLength); + b.HasIndex(x => x.UrlSlug); }); } diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs index f0b3d595f4..07897d0d5b 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs @@ -1,16 +1,215 @@ using System; +using System.IO; +using System.Threading.Tasks; +using Castle.DynamicProxy.Generators; using Shouldly; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; +using Volo.Abp.Domain.Entities; using Volo.CmsKit.Admin.Blogs; +using Xunit; namespace Volo.CmsKit.Blogs { public class BlogPostAdminAppService_Tests : CmsKitApplicationTestBase { private readonly IBlogPostAdminAppService blogPostAdminAppService; + private readonly CmsKitTestData cmsKitTestData; + private readonly IBlogPostRepository blogPostRepository; public BlogPostAdminAppService_Tests() { blogPostAdminAppService = GetRequiredService(); + cmsKitTestData = GetRequiredService(); + blogPostRepository = GetRequiredService(); } + + [Fact] + public async Task CreateAsync_ShouldWorkProperly_WithCorrectData() + { + var title = "My awesome new Post"; + var urlSlug = "my-awesome-new-post"; + var shortDescription = "This blog is all about awesomeness 🤗!"; + + var created = await blogPostAdminAppService.CreateAsync(new CreateUpdateBlogPostDto + { + BlogId = cmsKitTestData.Blog_Id, + Title = title, + UrlSlug = urlSlug, + ShortDescription = shortDescription + }); + + created.Id.ShouldNotBe(Guid.Empty); + + var blogPost = await blogPostRepository.GetAsync(created.Id); + + blogPost.Title.ShouldBe(title); + blogPost.UrlSlug.ShouldBe(urlSlug); + blogPost.ShortDescription.ShouldBe(shortDescription); + } + + [Fact] + public async Task CreateAsync_ShouldThrowException_WithNonExistingBlogId() + { + var title = "Another My Awesome New Post"; + var urlSlug = "another-my-awesome-new-post"; + var shortDescription = "This blog is all about awesomeness 🤗!"; + + var dto = new CreateUpdateBlogPostDto + { + // Non-existing Id + BlogId = Guid.NewGuid(), + Title = title, + UrlSlug = urlSlug, + ShortDescription = shortDescription + }; + + var exception = await Should.ThrowAsync(async () => + await blogPostAdminAppService.CreateAsync(dto)); + + exception.EntityType.ShouldBe(typeof(Blog)); + } + + [Fact] + public async Task GetAsync_ShouldWorkProperly_WithExistingId() + { + var blogPost = await blogPostAdminAppService.GetAsync(cmsKitTestData.BlogPost_1_Id); + + blogPost.Title.ShouldBe(cmsKitTestData.BlogPost_1_Title); + blogPost.UrlSlug.ShouldBe(cmsKitTestData.BlogPost_1_UrlSlug); + } + + [Fact] + public async Task GetAsync_ShouldThrowException_WithNonExistingId() + { + var nonExistingId = Guid.NewGuid(); + var exception = await Should.ThrowAsync(async () => + await blogPostAdminAppService.GetAsync(nonExistingId)); + + exception.EntityType.ShouldBe(typeof(BlogPost)); + exception.Id.ShouldBe(nonExistingId); + } + + [Fact] + public async Task GetByUrlSlugAsync_ShouldWorkProperly_WithExistingUrlSlug() + { + var blogPost = await blogPostAdminAppService.GetByUrlSlugAsync(cmsKitTestData.BlogPost_1_UrlSlug); + + blogPost.Id.ShouldBe(cmsKitTestData.BlogPost_1_Id); + blogPost.Title.ShouldBe(cmsKitTestData.BlogPost_1_Title); + } + + [Fact] + public async Task GetByUrlSlugAsync_ShouldThrowException_WithNonExistingUrlSlug() + { + var nonExistingUrlSlug = "any-other-url"; + var exception = await Should.ThrowAsync(async () => + await blogPostAdminAppService.GetByUrlSlugAsync(cmsKitTestData.Page_1_Url)); + + exception.EntityType.ShouldBe(typeof(BlogPost)); + } + + [Fact] + public async Task GetListAsync_ShouldWorkProperly_WithDefaultParameters() + { + var list = await blogPostAdminAppService.GetListAsync(new PagedAndSortedResultRequestDto()); + + list.ShouldNotBeNull(); + list.TotalCount.ShouldBe(2); + list.Items.ShouldNotBeEmpty(); + list.Items.Count.ShouldBe(2); + } + + [Fact] + public async Task UpdateAsync_ShouldWorkProperly_WithRegularDatas() + { + var shortDescription = "Another short description"; + var title = "[Solved] Another Blog Post"; + var urlSlug = "another-short-blog-post"; + + await blogPostAdminAppService.UpdateAsync(cmsKitTestData.BlogPost_2_Id, new CreateUpdateBlogPostDto + { + BlogId = cmsKitTestData.Blog_Id, + ShortDescription = shortDescription, + Title = title, + UrlSlug = urlSlug, + }); + + var blogPost = await blogPostRepository.GetAsync(cmsKitTestData.BlogPost_2_Id); + + blogPost.Title.ShouldBe(title); + blogPost.ShortDescription.ShouldBe(shortDescription); + blogPost.UrlSlug.ShouldBe(urlSlug); + } + + [Fact] + public async Task UpdateAsync_ShouldThrowException_WhileChangingWithNonExistingBlogId() + { + var nonExistingId = Guid.NewGuid(); + + var dto = new CreateUpdateBlogPostDto + { + BlogId = nonExistingId, + Title = cmsKitTestData.Page_2_Title, + UrlSlug = cmsKitTestData.BlogPost_2_UrlSlug + }; + + var exception = await Should.ThrowAsync(async () => + await blogPostAdminAppService.UpdateAsync(cmsKitTestData.BlogPost_2_Id, dto)); + + exception.EntityType.ShouldBe(typeof(Blog)); + exception.Id.ShouldBe(nonExistingId); + } + + [Fact] + public async Task UpdateAsync_ShouldThrowException_WhileUpdatingWithAlreadyExistingSlug() + { + var dto = new CreateUpdateBlogPostDto + { + BlogId = cmsKitTestData.Blog_Id, + Title = "Some new title", + UrlSlug = cmsKitTestData.BlogPost_1_UrlSlug + }; + + var exception = await Should.ThrowAsync(async () => + await blogPostAdminAppService.UpdateAsync(cmsKitTestData.BlogPost_2_Id, dto)); + + exception.UrlSlug.ShouldBe(cmsKitTestData.BlogPost_1_UrlSlug); + } + + [Fact] + public async Task DeleteAsync_ShouldWorkProperly_WithExistingId() + { + await blogPostAdminAppService.DeleteAsync(cmsKitTestData.Page_2_Id); + + var exception = await Should.ThrowAsync(async () => + await blogPostRepository.GetAsync(cmsKitTestData.Page_2_Id)); + + exception.EntityType.ShouldBe(typeof(BlogPost)); + exception.Id.ShouldBe(cmsKitTestData.Page_2_Id); + } + + [Fact] + public async Task SetCoverImage_ShouldNotThrowException_WithCorrectData() + { + using (var imageStream = GetSampleImageStream()) + { + await WithUnitOfWorkAsync(async () => + { + await blogPostAdminAppService.SetCoverImageAsync( + cmsKitTestData.BlogPost_2_Id, + new RemoteStreamContent(imageStream)); + }); + } + } + + private Stream GetSampleImageStream() + { + var assembly = GetType().Assembly; + var resourceName = "Volo.CmsKit.Data.BlogPostSample.png"; + + return assembly.GetManifestResourceStream(resourceName); + } + // SetCoverImage } } diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Data/BlogPostSample.png b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Data/BlogPostSample.png new file mode 100644 index 0000000000..117bc57c3d Binary files /dev/null and b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Data/BlogPostSample.png differ diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Volo.CmsKit.Application.Tests.csproj b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Volo.CmsKit.Application.Tests.csproj index 26c4be533f..bd5f553367 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Volo.CmsKit.Application.Tests.csproj +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Volo.CmsKit.Application.Tests.csproj @@ -5,6 +5,14 @@ Volo.CmsKit + + + + + + + + diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs index 66489f80e8..42b0605e5d 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs @@ -276,7 +276,7 @@ namespace Volo.CmsKit private async Task SeedBlogsAsync() { - var blog = await _blogRepository.InsertAsync(new Blog(_cmsKitTestData.BlogName)); + var blog = await _blogRepository.InsertAsync(new Blog(_cmsKitTestData.Blog_Id, _cmsKitTestData.BlogName)); await _blogPostRepository.InsertAsync(new BlogPost(_cmsKitTestData.BlogPost_1_Id, blog.Id, _cmsKitTestData.BlogPost_1_Title, _cmsKitTestData.BlogPost_1_UrlSlug, "Short desc 1")); diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs index 2da69a5ac6..117cf49b11 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs @@ -7,6 +7,7 @@ namespace Volo.CmsKit public class CmsKitTestData : ISingletonDependency { public Guid User1Id { get; } = Guid.NewGuid(); + public string User1UserName => "fake.user"; public Guid User2Id { get; } = Guid.NewGuid();