From 85cab4311d9123cff63816ace7bfb685727533c8 Mon Sep 17 00:00:00 2001 From: enisn Date: Tue, 2 Feb 2021 15:47:44 +0300 Subject: [PATCH] CmsKit - BlogPost Public logic in Repositories & AppServices --- .../Admin/Blogs/IBlogPostAdminAppService.cs | 8 +- .../Admin/Blogs/BlogPostAdminAppService.cs | 9 +- .../Admin/Blogs/BlogPostAdminController.cs | 6 +- .../Volo/CmsKit/Users/CmsUserDto.cs | 20 +++ ...msKitCommonApplicationAutoMapperProfile.cs | 3 + .../Volo/CmsKit/Blogs/Blog.cs | 2 +- .../Volo/CmsKit/Blogs/BlogPost.cs | 2 +- .../Volo/CmsKit/Blogs/BlogPostManager.cs | 10 +- .../BlogPostUrlSlugAlreadyExistException.cs | 10 +- .../Volo/CmsKit/Blogs/IBlogPostRepository.cs | 7 +- .../Volo/CmsKit/Blogs/IBlogRepository.cs | 2 + .../CmsKit/Blogs/EfCoreBlogPostRepository.cs | 32 ++++- .../Volo/CmsKit/Blogs/EfCoreBlogRepository.cs | 6 + .../CmsKitDbContextModelCreatingExtensions.cs | 2 +- .../MongoDB/Blogs/MongoBlogPostRepository.cs | 34 ++++- .../MongoDB/Blogs/MongoBlogRepository.cs | 6 + .../CmsKit/Public/Blogs/BlogPostPublicDto.cs | 17 +++ .../Public/Blogs/IBlogPostPublicAppService.cs | 13 ++ .../Public/Blogs/BlogPostPublicAppService.cs | 41 ++++++ .../PublicApplicationAutoMapperProfile.cs | 6 +- .../Blogs/BlogPostAdminAppService_Tests.cs | 16 ++- .../Blogs/BlogPostRepository_Test.cs | 14 ++ .../Blogs/BlogRepository_Test.cs | 14 ++ .../MongoDB/Blogs/BlogPostRepository_Test.cs | 16 +++ .../MongoDB/Blogs/BlogRepository_Test.cs | 16 +++ .../Blogs/BlogPostRepository_Test.cs | 125 ++++++++++++++++++ .../Blogs/BlogRepository_Test.cs | 47 +++++++ 27 files changed, 448 insertions(+), 36 deletions(-) create mode 100644 modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Users/CmsUserDto.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs create mode 100644 modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogPostRepository_Test.cs create mode 100644 modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogRepository_Test.cs create mode 100644 modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogPostRepository_Test.cs create mode 100644 modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogRepository_Test.cs create mode 100644 modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs create mode 100644 modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs index 866c536b85..902f31f025 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs @@ -6,14 +6,14 @@ using Volo.Abp.Content; namespace Volo.CmsKit.Admin.Blogs { - public interface IBlogPostAdminAppService + public interface IBlogPostAdminAppService : ICrudAppService< - BlogPostDto, - Guid, + BlogPostDto, + Guid, PagedAndSortedResultRequestDto, CreateUpdateBlogPostDto> { - Task GetByUrlSlugAsync(string urlSlug); + Task GetByUrlSlugAsync(string blogUrlSlug, string urlSlug); Task SetCoverImageAsync(Guid id, RemoteStreamContent streamContent); 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 3b3d323132..3034311d70 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 @@ -28,6 +28,7 @@ namespace Volo.CmsKit.Admin.Blogs { protected readonly IBlogPostManager BlogPostManager; protected readonly IBlogPostRepository BlogPostRepository; + protected readonly IBlogRepository BlogRepository; protected readonly IBlobContainer BlobContainer; protected readonly ICmsUserLookupService UserLookupService; @@ -35,11 +36,13 @@ namespace Volo.CmsKit.Admin.Blogs IRepository repository, IBlogPostManager blogPostManager, IBlogPostRepository blogPostRepository, + IBlogRepository blogRepository, IBlobContainer blobContainer, ICmsUserLookupService userLookupService) : base(repository) { BlogPostManager = blogPostManager; BlogPostRepository = blogPostRepository; + BlogRepository = blogRepository; BlobContainer = blobContainer; UserLookupService = userLookupService; @@ -50,9 +53,11 @@ namespace Volo.CmsKit.Admin.Blogs DeletePolicyName = CmsKitAdminPermissions.BlogPosts.Delete; } - public virtual async Task GetByUrlSlugAsync(string urlSlug) + public virtual async Task GetByUrlSlugAsync(string blogUrlSlug, string urlSlug) { - var blogPost = await BlogPostRepository.GetByUrlSlugAsync(urlSlug); + var blog = await BlogRepository.GetByUrlSlugAsync(blogUrlSlug); + + var blogPost = await BlogPostRepository.GetByUrlSlugAsync(blog.Id, urlSlug); return MapToGetOutputDto(blogPost); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs index 0dc8d512ad..b71f731efd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs @@ -53,11 +53,11 @@ namespace Volo.CmsKit.Admin.Blogs } [HttpGet] - [Route("{urlSlug}")] + [Route("{blogUrlSlug}/{urlSlug}")] [Authorize(CmsKitAdminPermissions.BlogPosts.Default)] - public virtual Task GetByUrlSlugAsync(string urlSlug) + public virtual Task GetByUrlSlugAsync(string blogUrlSlug, string urlSlug) { - return BlogPostAdminAppService.GetByUrlSlugAsync(urlSlug); + return BlogPostAdminAppService.GetByUrlSlugAsync(blogUrlSlug, urlSlug); } [HttpGet] diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Users/CmsUserDto.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Users/CmsUserDto.cs new file mode 100644 index 0000000000..3600688f4b --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Users/CmsUserDto.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; + +namespace Volo.CmsKit.Users +{ + public class CmsUserDto : EntityDto + { + public virtual Guid? TenantId { get; protected set; } + + public virtual string UserName { get; protected set; } + + public virtual string Name { get; set; } + + public virtual string Surname { get; set; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationAutoMapperProfile.cs index e5044dc200..9d89ddadeb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationAutoMapperProfile.cs @@ -2,6 +2,7 @@ using Volo.CmsKit.Contents; using Volo.CmsKit.Pages; using Volo.CmsKit.Tags; +using Volo.CmsKit.Users; namespace Volo.CmsKit { @@ -10,6 +11,8 @@ namespace Volo.CmsKit public CmsKitCommonApplicationAutoMapperProfile() { CreateMap(); + + CreateMap(); } } } 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 1dc571d69f..75d319b33b 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 @@ -24,7 +24,7 @@ namespace Volo.CmsKit.Blogs public string UrlSlug { get; protected set; } - public Guid? TenantId { get; } + public Guid? TenantId { get; protected set; } public void SetName(string name) { 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 1ebe6d72d7..2a9f6673f2 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 @@ -20,7 +20,7 @@ namespace Volo.CmsKit.Blogs public string ShortDescription { get; protected set; } - public Guid? TenantId { get; } + public Guid? TenantId { get; protected set; } 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 6bbb772072..61198e0fad 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 @@ -24,7 +24,7 @@ namespace Volo.CmsKit.Blogs { await CheckBlogExistenceAsync(blogPost.BlogId); - await CheckUrlSlugExistenceAsync(blogPost.UrlSlug); + await CheckUrlSlugExistenceAsync(blogPost.BlogId, blogPost.UrlSlug); return await blogPostRepository.InsertAsync(blogPost); } @@ -33,16 +33,16 @@ namespace Volo.CmsKit.Blogs { await CheckBlogExistenceAsync(blogPost.BlogId); - await CheckUrlSlugExistenceAsync(blogPost.UrlSlug); + await CheckUrlSlugExistenceAsync(blogPost.BlogId, blogPost.UrlSlug); await blogPostRepository.UpdateAsync(blogPost); } - private async Task CheckUrlSlugExistenceAsync(string urlSlug) + private async Task CheckUrlSlugExistenceAsync(Guid blogId, string urlSlug) { - if (await blogPostRepository.SlugExistsAsync(urlSlug)) + if (await blogPostRepository.SlugExistsAsync(blogId, urlSlug)) { - throw new BlogPostUrlSlugAlreadyExistException(urlSlug); + throw new BlogPostUrlSlugAlreadyExistException(blogId, urlSlug); } } 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 c21ccfa8e7..b000f5996d 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 @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Volo.Abp; namespace Volo.CmsKit.Blogs @@ -17,15 +13,19 @@ namespace Volo.CmsKit.Blogs { } - public BlogPostUrlSlugAlreadyExistException(string urlSlug) + public BlogPostUrlSlugAlreadyExistException(Guid blogId, string urlSlug) { UrlSlug = urlSlug; + BlogId = blogId; Code = CmsKitErrorCodes.Blogs.UrlSlugAlreadyExist; WithData(nameof(UrlSlug), UrlSlug); + WithData(nameof(BlogId), BlogId); } public string UrlSlug { get; } + + public Guid BlogId { get; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs index a9e35e3794..fdb721d8d8 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; @@ -9,8 +10,10 @@ namespace Volo.CmsKit.Blogs { public interface IBlogPostRepository : IBasicRepository { - Task SlugExistsAsync(string slug); + Task SlugExistsAsync(Guid blogId, string slug, CancellationToken cancellationToken = default); - Task GetByUrlSlugAsync(string urlSlug); + Task GetByUrlSlugAsync(Guid blogId, string urlSlug, CancellationToken cancellationToken = default); + + Task> GetPagedListAsync(Guid blogId, int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs index 90e59587a2..152c17d615 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs @@ -1,9 +1,11 @@ using System; +using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; namespace Volo.CmsKit.Blogs { public interface IBlogRepository : IBasicRepository { + public Task GetByUrlSlugAsync(string urlSlug); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs index 09445da84d..1a6546d5fc 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs @@ -1,9 +1,15 @@ using Microsoft.EntityFrameworkCore; using System; +using System.Collections.Generic; +using System.Linq.Dynamic.Core; +using System.Security.Cryptography.X509Certificates; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using Volo.CmsKit.EntityFrameworkCore; +using System.Linq; +using System.Data.Common; namespace Volo.CmsKit.Blogs { @@ -13,16 +19,34 @@ namespace Volo.CmsKit.Blogs { } - public Task GetByUrlSlugAsync(string urlSlug) + public Task GetByUrlSlugAsync(Guid blogId, string urlSlug, CancellationToken cancellationToken = default) { - return GetAsync(x => x.UrlSlug.ToLower() == urlSlug); + return GetAsync(x => x.BlogId == blogId && x.UrlSlug.ToLower() == urlSlug, cancellationToken: cancellationToken); } - public async Task SlugExistsAsync(string slug) + public async Task> GetPagedListAsync(Guid blogId, int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default) + { + + var queryable = (await GetQueryableAsync()) + .Include(i => i.Creator) + .Where(x => x.BlogId == blogId); + + if (!sorting.IsNullOrWhiteSpace()) + { + queryable = queryable.OrderBy(sorting); + } + + return await queryable + .Skip(skipCount) + .Take(maxResultCount) + .ToListAsync(cancellationToken); + } + + public async Task SlugExistsAsync(Guid blogId, string slug, CancellationToken cancellationToken = default) { var dbSet = await GetDbSetAsync(); - return await dbSet.AnyAsync(x => x.UrlSlug.ToLower() == slug); + return await dbSet.AnyAsync(x => x.BlogId == blogId && x.UrlSlug.ToLower() == slug, cancellationToken); } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs index a43504642c..76211780f6 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using Volo.CmsKit.EntityFrameworkCore; @@ -10,5 +11,10 @@ namespace Volo.CmsKit.Blogs public EfCoreBlogRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) { } + + public Task GetByUrlSlugAsync(string urlSlug) + { + return GetAsync(x => x.UrlSlug == urlSlug); + } } } 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 ca64253676..57d1f5511c 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 @@ -213,7 +213,7 @@ namespace Volo.CmsKit.EntityFrameworkCore b.Property(p => p.ShortDescription).HasMaxLength(BlogPostConsts.MaxShortDescriptionLength); - b.HasIndex(x => x.UrlSlug); + b.HasIndex(x => new { x.UrlSlug, x.BlogId }); }); } else diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs index 166eda7f0d..638c219bb6 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs @@ -1,4 +1,8 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; @@ -12,16 +16,38 @@ namespace Volo.CmsKit.MongoDB.Blogs { } - public Task GetByUrlSlugAsync(string urlSlug) + public Task GetByUrlSlugAsync(Guid blogId, string urlSlug, CancellationToken cancellationToken = default) { - return GetAsync(x => x.UrlSlug.ToLower() == urlSlug); + return GetAsync(x => x.BlogId == blogId && x.UrlSlug.ToLower() == urlSlug, cancellationToken: cancellationToken); } - public async Task SlugExistsAsync(string slug) + public async Task> GetPagedListAsync(Guid blogId, int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(cancellationToken); + var blogPostQueryable = await GetQueryableAsync(); + + var queryable = blogPostQueryable + .Where(x => x.BlogId == blogId) + //.Join(dbContext.CmsUsers, outerKeySelector: x => x.CreatorId, innerKeySelector: x => x.Id, resultSelector: s => s) + ; + + if (!sorting.IsNullOrWhiteSpace()) + { + queryable = queryable.OrderBy(sorting); + } + + queryable = queryable + .Skip(skipCount) + .Take(maxResultCount); + + return await AsyncExecuter.ToListAsync(queryable, cancellationToken); + } + + public async Task SlugExistsAsync(Guid blogId, string slug, CancellationToken cancellationToken = default) { var queryable = await GetQueryableAsync(); - return await AsyncExecuter.AnyAsync(queryable, x => x.UrlSlug.ToLower() == slug); + return await AsyncExecuter.AnyAsync(queryable, x => x.BlogId == blogId && x.UrlSlug.ToLower() == slug, cancellationToken); } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs index 195c29f1f7..998edf6e67 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; using Volo.CmsKit.Blogs; @@ -10,5 +11,10 @@ namespace Volo.CmsKit.MongoDB.Blogs public MongoBlogRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) { } + + public Task GetByUrlSlugAsync(string urlSlug) + { + return GetAsync(x => x.UrlSlug == urlSlug); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs new file mode 100644 index 0000000000..94d3f3fdbc --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs @@ -0,0 +1,17 @@ +using System; +using Volo.Abp.Application.Dtos; +using Volo.CmsKit.Users; + +namespace Volo.CmsKit.Public.Blogs +{ + public class BlogPostPublicDto : AuditedEntityWithUserDto + { + public Guid BlogId { get; set; } + + public string Title { get; set; } + + public string UrlSlug { get; set; } + + public string ShortDescription { get; set; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs new file mode 100644 index 0000000000..de460f0764 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; + +namespace Volo.CmsKit.Public.Blogs +{ + public interface IBlogPostPublicAppService + { + Task> GetListAsync(string blogUrlSlug, PagedAndSortedResultRequestDto input); + + Task GetAsync(string blogUrlSlug, string blogPostUrlSlug); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs new file mode 100644 index 0000000000..907e7e7518 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.Public.Blogs +{ + public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPublicAppService + { + protected IBlogRepository BlogRepository { get; } + + protected IBlogPostRepository BlogPostRepository { get; } + + public BlogPostPublicAppService( + IBlogRepository blogRepository, + IBlogPostRepository blogPostRepository) + { + BlogRepository = blogRepository; + BlogPostRepository = blogPostRepository; + } + + public async Task GetAsync(string blogUrlSlug, string blogPostUrlSlug) + { + var blog = await BlogRepository.GetByUrlSlugAsync(blogUrlSlug); + + var blogPost = await BlogPostRepository.GetByUrlSlugAsync(blog.Id, blogPostUrlSlug); + + return ObjectMapper.Map(blogPost); + } + + public async Task> GetListAsync(string blogUrlSlug, PagedAndSortedResultRequestDto input) + { + var blog = await BlogRepository.GetByUrlSlugAsync(blogUrlSlug); + + var blogPosts = await BlogPostRepository.GetPagedListAsync(blog.Id, input.SkipCount, input.MaxResultCount, input.Sorting); + + return ObjectMapper.Map, List>(blogPosts); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs index a45eaff0b2..46dab5a9a1 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs @@ -1,8 +1,10 @@ using AutoMapper; using Volo.Abp.AutoMapper; +using Volo.CmsKit.Blogs; using Volo.CmsKit.Comments; using Volo.CmsKit.Contents; using Volo.CmsKit.Pages; +using Volo.CmsKit.Public.Blogs; using Volo.CmsKit.Public.Comments; using Volo.CmsKit.Public.Contents; using Volo.CmsKit.Public.Pages; @@ -16,7 +18,7 @@ namespace Volo.CmsKit.Public { public PublicApplicationAutoMapperProfile() { - CreateMap(); + CreateMap(); CreateMap() .Ignore(x=> x.Author); @@ -30,6 +32,8 @@ namespace Volo.CmsKit.Public CreateMap(); CreateMap(); + + CreateMap(MemberList.None); } } } 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 07897d0d5b..71bb043ce8 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 @@ -93,22 +93,32 @@ namespace Volo.CmsKit.Blogs [Fact] public async Task GetByUrlSlugAsync_ShouldWorkProperly_WithExistingUrlSlug() { - var blogPost = await blogPostAdminAppService.GetByUrlSlugAsync(cmsKitTestData.BlogPost_1_UrlSlug); + var blogPost = await blogPostAdminAppService.GetByUrlSlugAsync(cmsKitTestData.BlogUrlSlug, 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() + public async Task GetByUrlSlugAsync_ShouldThrowException_WithNonExistingBlogPostUrlSlug() { var nonExistingUrlSlug = "any-other-url"; var exception = await Should.ThrowAsync(async () => - await blogPostAdminAppService.GetByUrlSlugAsync(cmsKitTestData.Page_1_Url)); + await blogPostAdminAppService.GetByUrlSlugAsync(cmsKitTestData.BlogUrlSlug, nonExistingUrlSlug)); exception.EntityType.ShouldBe(typeof(BlogPost)); } + [Fact] + public async Task GetByUrlSlugAsync_ShouldThrowException_WithNonExistingBlogUrlSlug() + { + var nonExistingUrlSlug = "any-other-url"; + var exception = await Should.ThrowAsync(async () => + await blogPostAdminAppService.GetByUrlSlugAsync(nonExistingUrlSlug, cmsKitTestData.Page_1_Url)); + + exception.EntityType.ShouldBe(typeof(Blog)); + } + [Fact] public async Task GetListAsync_ShouldWorkProperly_WithDefaultParameters() { diff --git a/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogPostRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogPostRepository_Test.cs new file mode 100644 index 0000000000..d393ef943e --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogPostRepository_Test.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.CmsKit.Blogs; +using Volo.CmsKit.Pages; + +namespace Volo.CmsKit.EntityFrameworkCore.Blogs +{ + public class BlogPostRepository_Test : BlogPostRepository_Test + { + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogRepository_Test.cs new file mode 100644 index 0000000000..40b74d4064 --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogRepository_Test.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.EntityFrameworkCore.Blogs +{ + public class BlogRepository_Test : BlogRepository_Test + { + + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogPostRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogPostRepository_Test.cs new file mode 100644 index 0000000000..4bdec74132 --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogPostRepository_Test.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.CmsKit.Blogs; +using Xunit; + +namespace Volo.CmsKit.MongoDB.Blogs +{ + [Collection(MongoTestCollection.Name)] + public class BlogPostRepository_Test : BlogPostRepository_Test + { + + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogRepository_Test.cs new file mode 100644 index 0000000000..9cac7b473c --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogRepository_Test.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.CmsKit.Blogs; +using Xunit; + +namespace Volo.CmsKit.MongoDB.Blogs +{ + [Collection(MongoTestCollection.Name)] + public class BlogRepository_Test : BlogRepository_Test + { + + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs new file mode 100644 index 0000000000..efd07101cb --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs @@ -0,0 +1,125 @@ +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Modularity; +using Xunit; + +namespace Volo.CmsKit.Blogs +{ + public abstract class BlogPostRepository_Test : CmsKitTestBase + where TStartupModule : IAbpModule + { + private readonly CmsKitTestData testData; + private readonly IBlogPostRepository blogPostRepository; + + public BlogPostRepository_Test() + { + testData = GetRequiredService(); + blogPostRepository = GetRequiredService(); + } + + [Fact] + public async Task SlugExistsAsync_ShouldReturnTrue_WithExistingUrlSlug() + { + var result = await blogPostRepository.SlugExistsAsync(testData.Blog_Id, testData.BlogPost_1_UrlSlug); + + result.ShouldBeTrue(); + } + + [Fact] + public async Task SlugExistsAsync_ShouldReturnFalse_WithNonExistingUrlSlug() + { + var nonExistingSlug = "any-other-url-slug"; + + var result = await blogPostRepository.SlugExistsAsync(testData.Blog_Id, nonExistingSlug); + + result.ShouldBeFalse(); + } + + [Fact] + public async Task SlugExistsAsync_ShouldReturnFalse_WithNonExistingBlogId() + { + var nonExistingBlogId = Guid.NewGuid(); + + var result = await blogPostRepository.SlugExistsAsync(nonExistingBlogId, testData.BlogPost_1_UrlSlug); + + result.ShouldBeFalse(); + } + + [Fact] + public async Task GetByUrlSlugAsync_ShouldWorkProperly_WithCorrectParameters() + { + var blogPost = await blogPostRepository.GetByUrlSlugAsync(testData.Blog_Id, testData.BlogPost_1_UrlSlug); + + blogPost.ShouldNotBeNull(); + blogPost.Id.ShouldBe(testData.BlogPost_1_Id); + blogPost.UrlSlug.ShouldBe(testData.BlogPost_1_UrlSlug); + } + + [Fact] + public async Task GetByUrlSlugAsync_ShouldThrowException_WithNonExistingBlogPostUrlSlug() + { + var nonExistingSlugUrl = "absolutely-non-existing-url"; + var exception = await Should.ThrowAsync( + async () => await blogPostRepository.GetByUrlSlugAsync(testData.Blog_Id, nonExistingSlugUrl)); + + exception.ShouldNotBeNull(); + exception.EntityType.ShouldBe(typeof(BlogPost)); + } + + [Fact] + public async Task GetByUrlSlugAsync_ShouldThrowException_WithNonExistingBlogId() + { + var nonExistingBlogId = Guid.NewGuid(); + var exception = await Should.ThrowAsync( + async () => await blogPostRepository.GetByUrlSlugAsync(nonExistingBlogId, testData.BlogPost_1_UrlSlug)); + + exception.ShouldNotBeNull(); + exception.EntityType.ShouldBe(typeof(BlogPost)); + } + + [Fact] + public async Task GetPagedListAsync_ShouldWorkProperly_WithBlogId_WhileGetting10_WithoutSorting() + { + var result = await blogPostRepository.GetPagedListAsync(testData.Blog_Id, 0, 10, default); + + result.ShouldNotBeNull(); + result.ShouldNotBeEmpty(); + result.Count.ShouldBe(2); + } + + [Fact] + public async Task GetPagedListAsync_ShouldWorkProperly_WithBlogId_WhileGetting1_WithoutSorting() + { + var result = await blogPostRepository.GetPagedListAsync(testData.Blog_Id, default, 1, default); + + result.ShouldNotBeNull(); + result.ShouldNotBeEmpty(); + result.Count.ShouldBe(1); + } + + [Fact] + public async Task GetPagedListAsync_ShouldWorkProperly_WithBlogId_WhileGetting1InPage2_WithoutSorting() + { + var result = await blogPostRepository.GetPagedListAsync(testData.Blog_Id, 1, 1, default); + + result.ShouldNotBeNull(); + result.ShouldNotBeEmpty(); + result.Count.ShouldBe(1); + } + + [Fact] + public async Task GetPagedListAsync_ShouldWorkProperly_WithBlogId_WhileGetting10_WithSortingByTitle() + { + var result = await blogPostRepository.GetPagedListAsync(testData.Blog_Id, default, 10, nameof(BlogPost.Title)); + + result.ShouldNotBeNull(); + result.ShouldNotBeEmpty(); + result.Count.ShouldBe(2); + } + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs new file mode 100644 index 0000000000..1f425ff7f7 --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs @@ -0,0 +1,47 @@ +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Modularity; +using Xunit; + +namespace Volo.CmsKit.Blogs +{ + public abstract class BlogRepository_Test : CmsKitTestBase + where TStartupModule : IAbpModule + { + private readonly CmsKitTestData testData; + private readonly IBlogRepository blogRepository; + + public BlogRepository_Test() + { + this.testData = GetRequiredService(); + this.blogRepository = GetRequiredService(); + } + + [Fact] + public async Task GetByUrlSlugAsync_ShouldWorkProperly_WithExistingSlug() + { + var blog = await blogRepository.GetByUrlSlugAsync(testData.BlogUrlSlug); + + blog.ShouldNotBeNull(); + blog.UrlSlug.ShouldBe(testData.BlogUrlSlug); + blog.Id.ShouldBe(testData.Blog_Id); + } + + [Fact] + public async Task GetByUrlSlugAsync_ShouldThrowException_WithNonExistingSlug() + { + var nonExistingSlug = "some-blog-slug-that-doesnt-exist"; + + var exception = await Should.ThrowAsync( + async () => await blogRepository.GetByUrlSlugAsync(nonExistingSlug)); + + exception.ShouldNotBeNull(); + exception.EntityType.ShouldBe(typeof(Blog)); + } + } +}