Browse Source

Merge pull request #7845 from abpframework/cms-kit/blogs-refactorings

Cms Kit - BlogPosts & BlogFeatures Refactoring
pull/7868/head
İlkay İlknur 6 years ago
committed by GitHub
parent
commit
26f7f9bff2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs
  2. 8
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs
  3. 101
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs
  4. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs
  5. 8
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs
  6. 12
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/BlogFeatureCacheItem.cs
  7. 24
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/BlogFeatureCacheKey.cs
  8. 14
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/IBlogFeatureCacheManager.cs
  9. 24
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureAppService.cs
  10. 46
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureCacheManager.cs
  11. 30
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureChangedHandler.cs
  12. 5
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationAutoMapperProfile.cs
  13. 17
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogFeatureChangedEto.cs
  14. 8
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs
  15. 22
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogFeatureManager.cs
  16. 11
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs
  17. 40
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs
  18. 9
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/DefaultBlogFeatureProvider.cs
  19. 17
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogFeatureManager.cs
  20. 14
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostManager.cs
  21. 62
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs
  22. 2
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs
  23. 40
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs
  24. 4
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs
  25. 2
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs
  26. 8
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs
  27. 2
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml
  28. 3
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml
  29. 29
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs
  30. 66
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostPublicAppService_Tests.cs
  31. 47
      modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Blogs/BlogPostManager_Tests.cs
  32. 24
      modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs
  33. 37
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs
  34. 4
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs

2
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs

@ -14,8 +14,6 @@ namespace Volo.CmsKit.Admin.Blogs
CreateBlogPostDto,
UpdateBlogPostDto>
{
Task<BlogPostDto> GetBySlugAsync(string blogSlug, string slug);
Task SetCoverImageAsync(Guid id, RemoteStreamContent streamContent);
Task<RemoteStreamContent> GetCoverImageAsync(Guid id);

8
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs

@ -18,13 +18,13 @@ namespace Volo.CmsKit.Admin.Blogs
{
protected IBlogFeatureRepository BlogFeatureRepository { get; }
protected IBlogFeatureManager BlogFeatureManager { get; }
protected BlogFeatureManager BlogFeatureManager { get; }
protected IDistributedEventBus EventBus { get; }
public BlogFeatureAdminAppService(
IBlogFeatureRepository blogFeatureRepository,
IBlogFeatureManager blogFeatureManager,
BlogFeatureManager blogFeatureManager,
IDistributedEventBus eventBus)
{
BlogFeatureRepository = blogFeatureRepository;
@ -33,7 +33,7 @@ namespace Volo.CmsKit.Admin.Blogs
}
[Authorize(CmsKitAdminPermissions.Blogs.Features)]
public async Task<List<BlogFeatureDto>> GetListAsync(Guid blogId)
public virtual async Task<List<BlogFeatureDto>> GetListAsync(Guid blogId)
{
var blogFeatures = await BlogFeatureManager.GetListAsync(blogId);
@ -41,7 +41,7 @@ namespace Volo.CmsKit.Admin.Blogs
}
[Authorize(CmsKitAdminPermissions.Blogs.Features)]
public Task SetAsync(Guid blogId, BlogFeatureInputDto dto)
public virtual Task SetAsync(Guid blogId, BlogFeatureInputDto dto)
{
return BlogFeatureManager.SetAsync(blogId, dto.FeatureName, dto.IsEnabled);
}

101
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
@ -17,29 +18,20 @@ namespace Volo.CmsKit.Admin.Blogs
{
[RequiresGlobalFeature(typeof(BlogsFeature))]
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)]
public class BlogPostAdminAppService
: CrudAppService<
BlogPost,
BlogPostDto,
Guid,
PagedAndSortedResultRequestDto,
CreateBlogPostDto,
UpdateBlogPostDto>
, IBlogPostAdminAppService
public class BlogPostAdminAppService: CmsKitAppServiceBase, IBlogPostAdminAppService
{
protected IBlogPostManager BlogPostManager { get; }
protected BlogPostManager BlogPostManager { get; }
protected IBlogPostRepository BlogPostRepository { get; }
protected IBlogRepository BlogRepository { get; }
protected IBlobContainer<BlogPostCoverImageContainer> BlobContainer { get; }
protected ICmsUserLookupService UserLookupService { get; }
public BlogPostAdminAppService(
IRepository<BlogPost, Guid> repository,
IBlogPostManager blogPostManager,
BlogPostManager blogPostManager,
IBlogPostRepository blogPostRepository,
IBlogRepository blogRepository,
IBlobContainer<BlogPostCoverImageContainer> blobContainer,
ICmsUserLookupService userLookupService) : base(repository)
ICmsUserLookupService userLookupService)
{
BlogPostManager = blogPostManager;
BlogPostRepository = blogPostRepository;
@ -47,61 +39,50 @@ namespace Volo.CmsKit.Admin.Blogs
BlobContainer = blobContainer;
UserLookupService = userLookupService;
GetListPolicyName = CmsKitAdminPermissions.BlogPosts.Default;
GetPolicyName = CmsKitAdminPermissions.BlogPosts.Default;
CreatePolicyName = CmsKitAdminPermissions.BlogPosts.Create;
UpdatePolicyName = CmsKitAdminPermissions.BlogPosts.Update;
DeletePolicyName = CmsKitAdminPermissions.BlogPosts.Delete;
}
public virtual async Task<BlogPostDto> GetBySlugAsync(string blogSlug, string blogPostSlug)
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)]
public virtual async Task<BlogPostDto> CreateAsync(CreateBlogPostDto input)
{
var blog = await BlogRepository.GetBySlugAsync(blogSlug);
var author = await UserLookupService.GetByIdAsync(CurrentUser.GetId());
var blogPost = await BlogPostRepository.GetBySlugAsync(blog.Id, blogPostSlug);
var blog = await BlogRepository.GetAsync(input.BlogId);
return await MapToGetOutputDtoAsync(blogPost);
}
var blogPost = await BlogPostManager.CreateAsync(
author,
blog,
input.Title,
input.Slug,
input.ShortDescription,
CurrentTenant.Id);
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)]
public override async Task<BlogPostDto> CreateAsync(CreateBlogPostDto input)
{
_ = await UserLookupService.GetByIdAsync(CurrentUser.GetId());
var entity = await BlogPostManager
.CreateAsync(
new BlogPost(
GuidGenerator.Create(),
input.BlogId,
input.Title,
input.Slug,
input.ShortDescription));
return await MapToGetOutputDtoAsync(entity);
await BlogPostRepository.InsertAsync(blogPost);
return ObjectMapper.Map<BlogPost, BlogPostDto>(blogPost);
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Update)]
public override async Task<BlogPostDto> UpdateAsync(Guid id, UpdateBlogPostDto input)
public virtual async Task<BlogPostDto> UpdateAsync(Guid id, UpdateBlogPostDto input)
{
var blogPost = await BlogPostRepository.GetAsync(id);
blogPost.SetTitle(input.Title);
blogPost.SetShortDescription(input.ShortDescription);
if (blogPost.Slug != input.Slug)
{
await BlogPostManager.SetSlugUrlAsync(blogPost, input.Slug);
}
MapToEntity(input, blogPost);
await BlogPostManager.UpdateAsync(blogPost);
await BlogPostRepository.UpdateAsync(blogPost);
return await MapToGetOutputDtoAsync(blogPost);
return ObjectMapper.Map<BlogPost,BlogPostDto>(blogPost);
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Update)]
public virtual async Task SetCoverImageAsync(Guid id, RemoteStreamContent streamContent)
{
await Repository.GetAsync(id);
await BlogPostRepository.GetAsync(id);
using (var stream = streamContent.GetStream())
{
@ -109,11 +90,43 @@ namespace Volo.CmsKit.Admin.Blogs
}
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)]
public virtual async Task<RemoteStreamContent> GetCoverImageAsync(Guid id)
{
var stream = await BlobContainer.GetAsync(id.ToString());
return new RemoteStreamContent(stream);
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)]
public virtual async Task<BlogPostDto> GetAsync(Guid id)
{
var blogPost = await BlogPostRepository.GetAsync(id);
return ObjectMapper.Map<BlogPost, BlogPostDto>(blogPost);
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)]
public virtual async Task<PagedResultDto<BlogPostDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{
if (input.Sorting.IsNullOrEmpty())
{
input.Sorting = nameof(BlogPost.CreationTime) + " desc";
}
var blogPosts = await BlogPostRepository.GetPagedListAsync(input.SkipCount, input.MaxResultCount, input.Sorting, includeDetails: true);
var count = await BlogPostRepository.GetCountAsync();
return new PagedResultDto<BlogPostDto>(
count,
ObjectMapper.Map<List<BlogPost>, List<BlogPostDto>>(blogPosts));
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Delete)]
public virtual async Task DeleteAsync(Guid id)
{
await BlogPostRepository.DeleteAsync(id);
}
}
}

2
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs

@ -39,8 +39,6 @@ namespace Volo.CmsKit.Admin
CreateMap<Blog, BlogDto>();
CreateMap<BlogFeature, BlogFeatureDto>();
CreateMap<TagEntityTypeDefiniton, TagDefinitionDto>(MemberList.Destination);
CreateMap<MediaDescriptor, MediaDescriptorDto>();

8
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs

@ -52,14 +52,6 @@ namespace Volo.CmsKit.Admin.Blogs
return BlogPostAdminAppService.GetAsync(id);
}
[HttpGet]
[Route("{blogSlug}/{blogPostSlug}")]
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)]
public virtual Task<BlogPostDto> GetBySlugAsync(string blogSlug, string blogPostSlug)
{
return BlogPostAdminAppService.GetBySlugAsync(blogSlug, blogPostSlug);
}
[HttpGet]
[Route("{id}/cover-image")]
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)]

12
modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/BlogFeatureCacheItem.cs

@ -0,0 +1,12 @@
using System;
namespace Volo.CmsKit.Blogs
{
[Serializable]
public class BlogFeatureCacheItem
{
public Guid Id { get; set; }
public string FeatureName { get; set; }
public bool IsEnabled { get; set; }
}
}

24
modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/BlogFeatureCacheKey.cs

@ -0,0 +1,24 @@
using JetBrains.Annotations;
using System;
using Volo.Abp;
namespace Volo.CmsKit.Blogs
{
public class BlogFeatureCacheKey
{
public BlogFeatureCacheKey(Guid id, [NotNull] string featureName)
{
Id = id;
FeatureName = Check.NotNullOrEmpty(featureName, nameof(featureName));
}
public Guid Id { get; set; }
public string FeatureName { get; set; }
public override string ToString()
{
return $"BlogFeature_{Id}_{FeatureName}";
}
}
}

14
modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/IBlogFeatureCacheManager.cs

@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Volo.CmsKit.Blogs
{
public interface IBlogFeatureCacheManager
{
Task<BlogFeatureDto> AddOrGetAsync(Guid blogId, string featureName, Func<Task<BlogFeatureDto>> factory);
Task ClearAsync(Guid blogId, string featureName);
}
}

24
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureAppService.cs

@ -2,7 +2,6 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.EventBus.Distributed;
namespace Volo.CmsKit.Blogs
{
@ -10,32 +9,31 @@ namespace Volo.CmsKit.Blogs
{
protected virtual IBlogFeatureRepository BlogFeatureRepository { get; }
protected virtual IBlogFeatureCacheManager BlogFeatureCacheManager { get; }
protected virtual IDistributedCache<BlogFeatureCacheItem, BlogFeatureCacheKey> Cache { get; }
public BlogFeatureAppService(
IBlogFeatureRepository blogFeatureRepository,
IBlogFeatureCacheManager blogFeatureCacheManager)
IDistributedCache<BlogFeatureCacheItem, BlogFeatureCacheKey> blogFeatureCacheManager)
{
BlogFeatureRepository = blogFeatureRepository;
BlogFeatureCacheManager = blogFeatureCacheManager;
Cache = blogFeatureCacheManager;
}
public virtual Task<BlogFeatureDto> GetOrDefaultAsync(Guid blogId, string featureName)
public virtual async Task<BlogFeatureDto> GetOrDefaultAsync(Guid blogId, string featureName)
{
return BlogFeatureCacheManager
.AddOrGetAsync(
blogId,
featureName,
()=> GetOrDefaultFroRepositoryAsync(blogId, featureName)
);
var cacheItem = await Cache.GetOrAddAsync(
new BlogFeatureCacheKey(blogId, featureName),
()=> GetOrDefaultFroRepositoryAsync(blogId, featureName));
return ObjectMapper.Map<BlogFeatureCacheItem, BlogFeatureDto>(cacheItem);
}
protected virtual async Task<BlogFeatureDto> GetOrDefaultFroRepositoryAsync(Guid blogId, string featureName)
protected virtual async Task<BlogFeatureCacheItem> GetOrDefaultFroRepositoryAsync(Guid blogId, string featureName)
{
var feature = await BlogFeatureRepository.FindAsync(blogId, featureName);
var blogFeature = feature ?? new BlogFeature(blogId, featureName);
return ObjectMapper.Map<BlogFeature, BlogFeatureDto>(blogFeature);
return ObjectMapper.Map<BlogFeature, BlogFeatureCacheItem>(blogFeature);
}
}
}

46
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureCacheManager.cs

@ -1,46 +0,0 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
namespace Volo.CmsKit.Blogs
{
public class BlogFeatureCacheManager : IBlogFeatureCacheManager, ITransientDependency
{
protected IDistributedCache<BlogFeatureDto> Cache { get; }
public BlogFeatureCacheManager(IDistributedCache<BlogFeatureDto> cache)
{
Cache = cache;
}
public async Task<BlogFeatureDto> AddOrGetAsync(Guid blogId, string featureName, Func<Task<BlogFeatureDto>> factory)
{
return await Cache.GetOrAddAsync(
GetCacheKey(blogId, featureName),
factory,
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1)
});
}
public Task ClearAsync(Guid blogId, string featureName)
{
return Cache.RemoveAsync(GetCacheKey(blogId, featureName));
}
private string GetCacheKey(Guid blogId, [NotNull] string featureName)
{
Check.NotNullOrWhiteSpace(featureName, nameof(featureName));
return $"{blogId}_{featureName}";
}
}
}

30
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureChangedHandler.cs

@ -1,22 +1,38 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
namespace Volo.CmsKit.Blogs
{
public class BlogFeatureChangedHandler : IDistributedEventHandler<BlogFeatureChangedEto>, ITransientDependency
public class BlogFeatureChangedHandler :
ILocalEventHandler<EntityCreatedEventData<BlogFeature>>,
ILocalEventHandler<EntityUpdatedEventData<BlogFeature>>,
ITransientDependency
{
protected IDistributedCache<BlogFeatureDto> Cache { get; }
protected IDistributedCache<BlogFeatureCacheItem, BlogFeatureCacheKey> Cache { get; }
public BlogFeatureChangedHandler(IDistributedCache<BlogFeatureDto> cache)
public BlogFeatureChangedHandler(
IDistributedCache<BlogFeatureCacheItem, BlogFeatureCacheKey> cache)
{
Cache = cache;
}
public async Task HandleEventAsync(BlogFeatureChangedEto eventData)
public Task RemoveFromCacheAsync(Guid blogId, string featureName)
{
await Cache.RemoveAsync($"{eventData.BlogId}_{eventData.FeatureName}");
return Cache.RemoveAsync(new BlogFeatureCacheKey(blogId, featureName));
}
public Task HandleEventAsync(EntityCreatedEventData<BlogFeature> eventData)
{
return RemoveFromCacheAsync(eventData.Entity.BlogId, eventData.Entity.FeatureName);
}
public Task HandleEventAsync(EntityUpdatedEventData<BlogFeature> eventData)
{
return RemoveFromCacheAsync(eventData.Entity.BlogId, eventData.Entity.FeatureName);
}
}
}

5
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationAutoMapperProfile.cs

@ -1,4 +1,5 @@
using AutoMapper;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Pages;
using Volo.CmsKit.Tags;
@ -13,6 +14,10 @@ namespace Volo.CmsKit
CreateMap<Tag, TagDto>();
CreateMap<CmsUser, CmsUserDto>();
CreateMap<BlogFeature, BlogFeatureCacheItem>();
CreateMap<BlogFeature, BlogFeatureDto>();
CreateMap<BlogFeatureCacheItem, BlogFeatureDto>().ReverseMap();
}
}
}

17
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogFeatureChangedEto.cs

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.EventBus;
namespace Volo.CmsKit.Blogs
{
[EventName("CmsKit.Blogs.BlogFeature.Changed")]
public class BlogFeatureChangedEto
{
public Guid BlogId { get; set; }
public string FeatureName { get; set; }
public bool IsEnabled { get; set; }
}
}

8
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs

@ -13,13 +13,5 @@ namespace Volo.CmsKit.Blogs
public static int MaxShortDescriptionLength { get; set; } = 256;
public const string EntityType = "BlogPost";
public const string CommentsFeatureName = CommentsFeature.Name;
public const string ReactionsFeatureName = ReactionsFeature.Name;
public const string RatingsFeatureName = RatingsFeature.Name;
public const string TagsFeatureName = TagsFeature.Name;
}
}

22
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogFeatureManager.cs

@ -3,30 +3,23 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Uow;
namespace Volo.CmsKit.Blogs
{
public class BlogFeatureManager : DomainService, IBlogFeatureManager
public class BlogFeatureManager : DomainService
{
protected IBlogFeatureRepository BlogFeatureRepository { get; }
protected IDefaultBlogFeatureProvider DefaultBlogFeatureProvider { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IDistributedEventBus EventBus { get; }
public BlogFeatureManager(
IBlogFeatureRepository blogFeatureRepository,
IDefaultBlogFeatureProvider defaultBlogFeatureProvider,
IUnitOfWorkManager unitOfWorkManager,
IDistributedEventBus eventBus)
IDefaultBlogFeatureProvider defaultBlogFeatureProvider)
{
BlogFeatureRepository = blogFeatureRepository;
DefaultBlogFeatureProvider = defaultBlogFeatureProvider;
UnitOfWorkManager = unitOfWorkManager;
EventBus = eventBus;
}
public async Task<List<BlogFeature>> GetListAsync(Guid blogId)
@ -53,15 +46,6 @@ namespace Volo.CmsKit.Blogs
blogFeature.IsEnabled = isEnabled;
await BlogFeatureRepository.UpdateAsync(blogFeature);
}
await UnitOfWorkManager.Current.SaveChangesAsync();
await EventBus.PublishAsync(new BlogFeatureChangedEto
{
BlogId = blogId,
FeatureName = featureName,
IsEnabled = isEnabled
});
}
}
}

11
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs

@ -8,7 +8,7 @@ using Volo.CmsKit.Users;
namespace Volo.CmsKit.Blogs
{
public class BlogPost : FullAuditedAggregateRootWithUser<Guid, CmsUser>, IMultiTenant
public class BlogPost : FullAuditedAggregateRoot<Guid>, IMultiTenant
{
public virtual Guid BlogId { get; protected set; }
@ -23,18 +23,25 @@ namespace Volo.CmsKit.Blogs
public virtual Guid? TenantId { get; protected set; }
[NotNull]
public Guid AuthorId { get; set; }
public virtual CmsUser Author { get; set; }
protected BlogPost()
{
}
public BlogPost(
internal BlogPost(
Guid id,
Guid blogId,
Guid authorId,
[NotNull] string title,
[NotNull] string slug,
[CanBeNull] string shortDescription = null) : base(id)
{
BlogId = blogId;
AuthorId = authorId;
SetTitle(title);
SetSlug(slug);
ShortDescription = shortDescription;

40
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs

@ -4,10 +4,11 @@ using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Services;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Blogs
{
public class BlogPostManager : DomainService, IBlogPostManager
public class BlogPostManager : DomainService
{
protected IBlogPostRepository BlogPostRepository { get; }
protected IBlogRepository BlogRepository { get; }
@ -20,20 +21,33 @@ namespace Volo.CmsKit.Blogs
BlogRepository = blogRepository;
}
public virtual async Task<BlogPost> CreateAsync(BlogPost blogPost)
public virtual async Task<BlogPost> CreateAsync(
[NotNull] CmsUser author,
[NotNull] Blog blog,
[NotNull] string title,
[NotNull] string slug,
[CanBeNull] string shortDescription = null,
[CanBeNull] Guid? tenantId = null)
{
await CheckBlogExistenceAsync(blogPost.BlogId);
Check.NotNull(author, nameof(author));
Check.NotNull(blog, nameof(blog));
Check.NotNullOrEmpty(title, nameof(title));
Check.NotNullOrEmpty(slug, nameof(slug));
await CheckSlugExistenceAsync(blogPost.BlogId, blogPost.Slug);
await CheckBlogExistenceAsync(blog.Id);
return await BlogPostRepository.InsertAsync(blogPost);
}
var blogPost = new BlogPost(
GuidGenerator.Create(),
blog.Id,
author.Id,
title,
slug,
shortDescription
);
public virtual async Task UpdateAsync(BlogPost blogPost)
{
await CheckBlogExistenceAsync(blogPost.BlogId);
await CheckSlugExistenceAsync(blog.Id, blogPost.Slug);
await BlogPostRepository.UpdateAsync(blogPost);
return blogPost;
}
public virtual async Task SetSlugUrlAsync(BlogPost blogPost, [NotNull] string newSlug)
@ -45,7 +59,7 @@ namespace Volo.CmsKit.Blogs
blogPost.SetSlug(newSlug);
}
private async Task CheckSlugExistenceAsync(Guid blogId, string slug)
protected virtual async Task CheckSlugExistenceAsync(Guid blogId, string slug)
{
if (await BlogPostRepository.SlugExistsAsync(blogId, slug))
{
@ -53,10 +67,12 @@ namespace Volo.CmsKit.Blogs
}
}
private async Task CheckBlogExistenceAsync(Guid blogId)
protected virtual async Task CheckBlogExistenceAsync(Guid blogId)
{
if (!await BlogRepository.ExistsAsync(blogId))
{
throw new EntityNotFoundException(typeof(Blog), blogId);
}
}
}
}

9
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/DefaultBlogFeatureProvider.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.CmsKit.GlobalFeatures;
namespace Volo.CmsKit.Blogs
{
@ -11,10 +12,10 @@ namespace Volo.CmsKit.Blogs
{
return Task.FromResult(new List<BlogFeature>
{
new BlogFeature(blogId, BlogPostConsts.CommentsFeatureName),
new BlogFeature(blogId, BlogPostConsts.ReactionsFeatureName),
new BlogFeature(blogId, BlogPostConsts.RatingsFeatureName),
new BlogFeature(blogId, BlogPostConsts.TagsFeatureName),
new BlogFeature(blogId, CommentsFeature.Name),
new BlogFeature(blogId, ReactionsFeature.Name),
new BlogFeature(blogId, RatingsFeature.Name),
new BlogFeature(blogId, TagsFeature.Name),
});
}
}

17
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogFeatureManager.cs

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.CmsKit.Blogs;
namespace Volo.CmsKit.Blogs
{
public interface IBlogFeatureManager : IDomainService
{
Task<List<BlogFeature>> GetListAsync(Guid blogId);
Task SetAsync(Guid blogId, string featureName, bool isEnabled);
}
}

14
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostManager.cs

@ -1,14 +0,0 @@
using JetBrains.Annotations;
using System.Threading.Tasks;
namespace Volo.CmsKit.Blogs
{
public interface IBlogPostManager
{
Task<BlogPost> CreateAsync(BlogPost blogPost);
Task UpdateAsync(BlogPost blogPost);
Task SetSlugUrlAsync(BlogPost blogPost, [NotNull] string newSlug);
}
}

62
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs

@ -1,18 +1,16 @@
using Microsoft.EntityFrameworkCore;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.CmsKit.EntityFrameworkCore;
using System.Linq;
using System.Data.Common;
using JetBrains.Annotations;
using Volo.Abp;
using Volo.Abp.Domain.Entities;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Blogs
{
@ -22,16 +20,22 @@ namespace Volo.CmsKit.Blogs
{
}
public async Task<BlogPost> GetBySlugAsync(Guid blogId, [NotNull] string slug,
public async Task<BlogPost> GetBySlugAsync(
Guid blogId,
[NotNull] string slug,
CancellationToken cancellationToken = default)
{
Check.NotNullOrEmpty(slug, nameof(slug));
return await (await WithDetailsAsync())
.Where(x =>
x.BlogId == blogId && x.Slug.ToLower() == slug)
.FirstOrDefaultAsync(cancellationToken: GetCancellationToken(cancellationToken))
?? throw new EntityNotFoundException(typeof(BlogPost));
var blogPost = await GetAsync(
x => x.BlogId == blogId && x.Slug.ToLower() == slug,
cancellationToken: GetCancellationToken(cancellationToken));
blogPost.Author = await (await GetDbContextAsync())
.Set<CmsUser>()
.FirstOrDefaultAsync(x =>x.Id == blogPost.AuthorId);
return blogPost;
}
public async Task<int> GetCountAsync(Guid blogId, CancellationToken cancellationToken = default)
@ -44,7 +48,11 @@ namespace Volo.CmsKit.Blogs
public async Task<List<BlogPost>> GetPagedListAsync(Guid blogId, int skipCount, int maxResultCount,
string sorting, bool includeDetails = false, CancellationToken cancellationToken = default)
{
var queryable = (await WithDetailsAsync())
var dbContext = await GetDbContextAsync();
var blogPostsDbSet = dbContext.Set<BlogPost>();
var usersDbSet = dbContext.Set<CmsUser>();
var queryable = blogPostsDbSet
.Where(x => x.BlogId == blogId);
if (!sorting.IsNullOrWhiteSpace())
@ -52,10 +60,21 @@ namespace Volo.CmsKit.Blogs
queryable = queryable.OrderBy(sorting);
}
return await queryable
.Skip(skipCount)
.Take(maxResultCount)
.ToListAsync(GetCancellationToken());
var combinedResult = await queryable
.Join(
usersDbSet,
o => o.AuthorId,
i => i.Id,
(blogPost,user) => new { blogPost, user })
.Skip(skipCount)
.Take(maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
return combinedResult.Select(s =>
{
s.blogPost.Author = s.user;
return s.blogPost;
}).ToList();
}
public async Task<bool> SlugExistsAsync(Guid blogId, [NotNull] string slug,
@ -63,13 +82,8 @@ namespace Volo.CmsKit.Blogs
{
Check.NotNullOrEmpty(slug, nameof(slug));
return await (await WithDetailsAsync()).AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug,
return await (await GetDbSetAsync()).AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug,
GetCancellationToken(cancellationToken));
}
public override async Task<IQueryable<BlogPost>> WithDetailsAsync()
{
return (await GetDbSetAsync()).Include(i => i.Creator);
}
}
}

2
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs

@ -214,6 +214,8 @@ namespace Volo.CmsKit.EntityFrameworkCore
b.Property(p => p.ShortDescription).HasMaxLength(BlogPostConsts.MaxShortDescriptionLength);
b.Property(p => p.AuthorId).IsRequired();
b.HasIndex(x => new { x.Slug, x.BlogId });
});

40
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs

@ -1,13 +1,12 @@
using MongoDB.Driver;
using JetBrains.Annotations;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Nito.AsyncEx;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;
@ -23,16 +22,21 @@ namespace Volo.CmsKit.MongoDB.Blogs
{
}
public Task<BlogPost> GetBySlugAsync(Guid blogId, [NotNull] string slug,
public async Task<BlogPost> GetBySlugAsync(Guid blogId, [NotNull] string slug,
CancellationToken cancellationToken = default)
{
Check.NotNullOrEmpty(slug, nameof(slug));
return GetAsync(x =>
var blogPost = await GetAsync(x =>
x.BlogId == blogId &&
x.Slug.ToLower() == slug,
includeDetails: true,
cancellationToken: GetCancellationToken(cancellationToken));
var dbContext = await GetDbContextAsync();
blogPost.Author = await dbContext.Collection<CmsUser>().AsQueryable().FirstOrDefaultAsync(x => x.Id == blogPost.AuthorId);
return blogPost;
}
public async Task<int> GetCountAsync(Guid blogId, CancellationToken cancellationToken = default)
@ -48,9 +52,10 @@ namespace Volo.CmsKit.MongoDB.Blogs
{
var token = GetCancellationToken(cancellationToken);
var dbContext = await GetDbContextAsync(token);
var blogPostQueryable = await WithDetailsAsync();
var blogPostQueryable = dbContext.Collection<BlogPost>().AsQueryable();
var usersQueryable = dbContext.Collection<CmsUser>().AsQueryable();
var queryable = blogPostQueryable
IQueryable<BlogPost> queryable = blogPostQueryable
.Where(x => x.BlogId == blogId);
if (!sorting.IsNullOrWhiteSpace())
@ -58,11 +63,22 @@ namespace Volo.CmsKit.MongoDB.Blogs
queryable = queryable.OrderBy(sorting);
}
queryable = queryable
.Skip(skipCount)
.Take(maxResultCount);
var combinedQueryable = queryable
.Join(
usersQueryable,
o => o.AuthorId,
i => i.Id,
(blogPost, user) => new { blogPost, user })
.Skip(skipCount)
.Take(maxResultCount);
var combinedResult = await AsyncExecuter.ToListAsync(combinedQueryable, GetCancellationToken(cancellationToken));
return await AsyncExecuter.ToListAsync(queryable, token);
return combinedResult.Select(s =>
{
s.blogPost.Author = s.user;
return s.blogPost;
}).ToList();
}
public async Task<bool> SlugExistsAsync(Guid blogId, [NotNull] string slug,

4
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs

@ -5,7 +5,7 @@ using Volo.CmsKit.Users;
namespace Volo.CmsKit.Public.Blogs
{
[Serializable]
public class BlogPostPublicDto : AuditedEntityWithUserDto<Guid, CmsUserDto>
public class BlogPostPublicDto : AuditedEntityDto<Guid>
{
public Guid BlogId { get; set; }
@ -14,5 +14,7 @@ namespace Volo.CmsKit.Public.Blogs
public string Slug { get; set; }
public string ShortDescription { get; set; }
public CmsUserDto Author { get; set; }
}
}

2
modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs

@ -34,8 +34,6 @@ namespace Volo.CmsKit.Public
CreateMap<Page, PageDto>();
CreateMap<BlogPost, BlogPostPublicDto>(MemberList.None);
CreateMap<BlogFeature, BlogFeatureDto>();
}
}
}

8
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs

@ -48,22 +48,22 @@ namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs
if (GlobalFeatureManager.Instance.IsEnabled<CommentsFeature>())
{
CommentsFeature = await BlogFeatureAppService.GetOrDefaultAsync(BlogPost.BlogId, BlogPostConsts.CommentsFeatureName);
CommentsFeature = await BlogFeatureAppService.GetOrDefaultAsync(BlogPost.BlogId, GlobalFeatures.CommentsFeature.Name);
}
if (GlobalFeatureManager.Instance.IsEnabled<ReactionsFeature>())
{
ReactionsFeature = await BlogFeatureAppService.GetOrDefaultAsync(BlogPost.BlogId, BlogPostConsts.ReactionsFeatureName);
ReactionsFeature = await BlogFeatureAppService.GetOrDefaultAsync(BlogPost.BlogId, GlobalFeatures.ReactionsFeature.Name);
}
if (GlobalFeatureManager.Instance.IsEnabled<RatingsFeature>())
{
RatingsFeature = await BlogFeatureAppService.GetOrDefaultAsync(BlogPost.BlogId, BlogPostConsts.RatingsFeatureName);
RatingsFeature = await BlogFeatureAppService.GetOrDefaultAsync(BlogPost.BlogId, GlobalFeatures.RatingsFeature.Name);
}
if (GlobalFeatureManager.Instance.IsEnabled<TagsFeature>())
{
TagsFeature = await BlogFeatureAppService.GetOrDefaultAsync(BlogPost.BlogId, BlogPostConsts.TagsFeatureName);
TagsFeature = await BlogFeatureAppService.GetOrDefaultAsync(BlogPost.BlogId, GlobalFeatures.TagsFeature.Name);
}
}
}

2
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml

@ -16,7 +16,7 @@
@blog.Title
</abp-card-title>
<abp-card-subtitle>
@@@blog.Creator?.UserName
@@@blog.Author?.UserName
</abp-card-subtitle>
</abp-card-header>
<abp-card-body>

3
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml

@ -10,11 +10,10 @@
<abp-card>
<abp-card-header>
<abp-card-title>@Model.Title</abp-card-title>
<abp-card-subtitle>@Model.Creator?.UserName</abp-card-subtitle>
<abp-card-subtitle>@Model.Author?.UserName</abp-card-subtitle>
</abp-card-header>
<abp-card-body>
@*<img src="/api/cms-kit-public/blog-posts/@Model.Id/cover-image" class="card-img-top" style="max-width:200px;max-height:200px;" onerror="this.src='https://dummyimage.com/300x200/a3a3a3/fff.png'" />*@
@await Component.InvokeAsync(typeof(ContentViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,

29
modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs

@ -90,35 +90,6 @@ namespace Volo.CmsKit.Blogs
exception.Id.ShouldBe(nonExistingId);
}
[Fact]
public async Task GetBySlugAsync_ShouldWorkProperly_WithExistingSlug()
{
var blogPost = await blogPostAdminAppService.GetBySlugAsync(cmsKitTestData.BlogSlug, cmsKitTestData.BlogPost_1_Slug);
blogPost.Id.ShouldBe(cmsKitTestData.BlogPost_1_Id);
blogPost.Title.ShouldBe(cmsKitTestData.BlogPost_1_Title);
}
[Fact]
public async Task GetBySlugAsync_ShouldThrowException_WithNonExistingBlogPostSlug()
{
var nonExistingSlug = "any-other-url";
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () =>
await blogPostAdminAppService.GetBySlugAsync(cmsKitTestData.BlogSlug, nonExistingSlug));
exception.EntityType.ShouldBe(typeof(BlogPost));
}
[Fact]
public async Task GetBySlugAsync_ShouldThrowException_WithNonExistingBlogSlug()
{
var nonExistingSlug = "any-other-url";
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () =>
await blogPostAdminAppService.GetBySlugAsync(nonExistingSlug, cmsKitTestData.Page_1_Slug));
exception.EntityType.ShouldBe(typeof(Blog));
}
[Fact]
public async Task GetListAsync_ShouldWorkProperly_WithDefaultParameters()
{

66
modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostPublicAppService_Tests.cs

@ -0,0 +1,66 @@
using Shouldly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
using Volo.CmsKit.Public.Blogs;
using Xunit;
namespace Volo.CmsKit.Blogs
{
public class BlogPostPublicAppService_Tests : CmsKitApplicationTestBase
{
private readonly IBlogPostPublicAppService blogPostAppService;
private readonly CmsKitTestData cmsKitTestData;
public BlogPostPublicAppService_Tests()
{
blogPostAppService = GetRequiredService<IBlogPostPublicAppService>();
cmsKitTestData = GetRequiredService<CmsKitTestData>();
}
[Fact]
public async Task GetListAsync_ShouldWorkProperly_WithExistingBlog()
{
var blogPosts = await blogPostAppService.GetListAsync(cmsKitTestData.BlogSlug, new PagedAndSortedResultRequestDto { MaxResultCount = 2 });
blogPosts.ShouldNotBeNull();
blogPosts.TotalCount.ShouldBe(2);
blogPosts.Items.ShouldNotBeEmpty();
blogPosts.Items.Count.ShouldBe(2);
}
[Fact]
public async Task GetAsync_ShouldWorkProperly_WithExistingSlug()
{
var blogPost = await blogPostAppService.GetAsync(cmsKitTestData.BlogSlug, cmsKitTestData.BlogPost_1_Slug);
blogPost.Id.ShouldBe(cmsKitTestData.BlogPost_1_Id);
blogPost.Title.ShouldBe(cmsKitTestData.BlogPost_1_Title);
}
[Fact]
public async Task GetAsync_ShouldThrowException_WithNonExistingBlogPostSlug()
{
var nonExistingSlug = "any-other-url";
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () =>
await blogPostAppService.GetAsync(cmsKitTestData.BlogSlug, nonExistingSlug));
exception.EntityType.ShouldBe(typeof(BlogPost));
}
[Fact]
public async Task GetAsync_ShouldThrowException_WithNonExistingBlogSlug()
{
var nonExistingSlug = "any-other-url";
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () =>
await blogPostAppService.GetAsync(nonExistingSlug, cmsKitTestData.Page_1_Slug));
exception.EntityType.ShouldBe(typeof(Blog));
}
}
}

47
modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Blogs/BlogPostManager_Tests.cs

@ -5,38 +5,45 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Guids;
using Volo.Abp.Users;
using Volo.CmsKit.Tags;
using Volo.CmsKit.Users;
using Xunit;
namespace Volo.CmsKit.Blogs
{
public class BlogPostManager_Tests : CmsKitDomainTestBase
{
private readonly IBlogPostManager blogPostManager;
private readonly BlogPostManager blogPostManager;
private readonly IGuidGenerator guidGenerator;
private readonly IBlogPostRepository blogPostRepository;
private readonly IBlogRepository blogRepository;
private readonly ICmsUserRepository userRepository;
private readonly CmsKitTestData cmsKitTestData;
public BlogPostManager_Tests()
{
this.blogPostManager = GetRequiredService<IBlogPostManager>();
this.guidGenerator = GetRequiredService<IGuidGenerator>();
this.blogPostRepository = GetRequiredService<IBlogPostRepository>();
this.cmsKitTestData = GetRequiredService<CmsKitTestData>();
blogPostManager = GetRequiredService<BlogPostManager>();
guidGenerator = GetRequiredService<IGuidGenerator>();
blogPostRepository = GetRequiredService<IBlogPostRepository>();
blogRepository = GetRequiredService<IBlogRepository>();
cmsKitTestData = GetRequiredService<CmsKitTestData>();
userRepository = GetRequiredService<ICmsUserRepository>();
}
[Fact]
public async Task CreateAsync_ShouldWorkProperly_WithCorrectData()
public async Task CreateAsync_ShouldWorkProperly_WithExistingUserAndBlog()
{
var title = "New blog post";
var slug = "new-blog-post";
var created = await blogPostManager.CreateAsync(
new BlogPost(guidGenerator.Create(), cmsKitTestData.Blog_Id, title, slug));
var author = await userRepository.GetAsync(cmsKitTestData.User1Id);
created.Id.ShouldNotBe(Guid.Empty);
var blog = await blogRepository.GetAsync(cmsKitTestData.Blog_Id);
var blogPost = await blogPostRepository.GetAsync(created.Id);
var blogPost = await blogPostManager.CreateAsync(author, blog, title, slug);
blogPost.Id.ShouldNotBe(Guid.Empty);
blogPost.Title.ShouldBe(title);
blogPost.Slug.ShouldBe(slug);
}
@ -44,25 +51,13 @@ namespace Volo.CmsKit.Blogs
[Fact]
public async Task CreateAsync_ShouldThrowException_WhenSlugAlreadyExists()
{
var blogPost = new BlogPost(guidGenerator.Create(), cmsKitTestData.Blog_Id, "Any New Title", cmsKitTestData.BlogPost_1_Slug);
await Should.ThrowAsync<BlogPostSlugAlreadyExistException>(async () =>
await blogPostManager.CreateAsync(blogPost));
}
[Fact]
public async Task UpdateAsync_ShoudlWorkProperly_WithCorrectData()
{
var newTitle = "Yet Another Post";
var blogPost = await blogPostRepository.GetAsync(cmsKitTestData.BlogPost_1_Id);
var author = await userRepository.GetAsync(cmsKitTestData.User1Id);
blogPost.SetTitle(newTitle);
var blog = await blogRepository.GetAsync(cmsKitTestData.Blog_Id);
await blogPostManager.UpdateAsync(blogPost);
var updated = await blogPostRepository.GetAsync(cmsKitTestData.BlogPost_1_Id);
updated.Title.ShouldBe(newTitle);
await Should.ThrowAsync<BlogPostSlugAlreadyExistException>(async () =>
await blogPostManager.CreateAsync(author, blog, "Any New Title", cmsKitTestData.BlogPost_1_Slug));
}
[Fact]

24
modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs

@ -60,6 +60,18 @@ namespace Volo.CmsKit.Blogs
blogPost.Slug.ShouldBe(testData.BlogPost_1_Slug);
}
[Fact]
public async Task GetBySlugAsync_ShouldHaveAuthor_WithCorrectParameters()
{
var blogPost = await blogPostRepository.GetBySlugAsync(testData.Blog_Id, testData.BlogPost_1_Slug);
blogPost.ShouldNotBeNull();
blogPost.Id.ShouldBe(testData.BlogPost_1_Id);
blogPost.Slug.ShouldBe(testData.BlogPost_1_Slug);
blogPost.Author.ShouldNotBeNull();
blogPost.Author.Id.ShouldBe(testData.User1Id);
}
[Fact]
public async Task GetBySlugAsync_ShouldThrowException_WithNonExistingBlogPostSlug()
{
@ -92,6 +104,18 @@ namespace Volo.CmsKit.Blogs
result.Count.ShouldBe(2);
}
[Fact]
public async Task GetPagedListAsync_ShouldHaveAuthor_WithBlogId_WhileGetting10_WithoutSorting()
{
var result = await blogPostRepository.GetPagedListAsync(testData.Blog_Id, 0, 10, default);
result.ShouldNotBeNull();
result.ShouldNotBeEmpty();
result.Count.ShouldBe(2);
result.ForEach(blogPost => blogPost.Author.ShouldNotBeNull());
}
[Fact]
public async Task GetPagedListAsync_ShouldWorkProperly_WithBlogId_WhileGetting1_WithoutSorting()
{

37
modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs

@ -42,6 +42,7 @@ namespace Volo.CmsKit
private readonly IBlogRepository _blogRepository;
private readonly IBlogFeatureRepository _blogFeatureRepository;
private readonly IBlogPostRepository _blogPostRepository;
private readonly BlogPostManager _blogPostManager;
private readonly IOptions<CmsKitOptions> _options;
private readonly IOptions<CmsKitTagOptions> _tagOptions;
private readonly IMediaDescriptorRepository _mediaDescriptorRepository;
@ -63,6 +64,7 @@ namespace Volo.CmsKit
IPageRepository pageRepository,
IBlogRepository blogRepository,
IBlogPostRepository blogPostRepository,
BlogPostManager blogPostmanager,
IBlogFeatureRepository blogFeatureRepository,
EntityTagManager entityTagManager,
IOptions<CmsKitOptions> options,
@ -86,6 +88,7 @@ namespace Volo.CmsKit
_pageRepository = pageRepository;
_blogRepository = blogRepository;
_blogPostRepository = blogPostRepository;
_blogPostManager = blogPostmanager;
_blogFeatureRepository = blogFeatureRepository;
_options = options;
_tagOptions = tagOptions;
@ -137,10 +140,13 @@ namespace Volo.CmsKit
{
await _cmsUserRepository.InsertAsync(new CmsUser(new UserData(_cmsKitTestData.User1Id, "user1",
"user1@volo.com",
"user", "1")));
"user", "1")),
autoSave: true);
await _cmsUserRepository.InsertAsync(new CmsUser(new UserData(_cmsKitTestData.User2Id, "user2",
"user2@volo.com",
"user", "2")));
"user", "2")),
autoSave: true);
}
private async Task SeedCommentsAsync()
@ -347,15 +353,30 @@ namespace Volo.CmsKit
private async Task SeedBlogsAsync()
{
var blog = await _blogManager.CreateAsync(_cmsKitTestData.BlogName, _cmsKitTestData.BlogSlug);
await _blogRepository.InsertAsync(blog);
var blog = await _blogRepository.InsertAsync(
await _blogManager.CreateAsync(_cmsKitTestData.BlogName, _cmsKitTestData.BlogSlug), autoSave: true);
_cmsKitTestData.Blog_Id = blog.Id;
await _blogPostRepository.InsertAsync(new BlogPost(_cmsKitTestData.BlogPost_1_Id, blog.Id, _cmsKitTestData.BlogPost_1_Title, _cmsKitTestData.BlogPost_1_Slug, "Short desc 1"));
await _blogPostRepository.InsertAsync(new BlogPost(_cmsKitTestData.BlogPost_2_Id, blog.Id, _cmsKitTestData.BlogPost_2_Title, _cmsKitTestData.BlogPost_2_Slug, "Short desc 2"));
var author = await _cmsUserRepository.GetAsync(_cmsKitTestData.User1Id);
_cmsKitTestData.BlogPost_1_Id =
(await _blogPostRepository.InsertAsync(
await _blogPostManager.CreateAsync(
author,
blog,
_cmsKitTestData.BlogPost_1_Title,
_cmsKitTestData.BlogPost_1_Slug,
"Short desc 1"))).Id;
_cmsKitTestData.BlogPost_2_Id =
(await _blogPostRepository.InsertAsync(
await _blogPostManager.CreateAsync(
author,
blog,
_cmsKitTestData.BlogPost_2_Title,
_cmsKitTestData.BlogPost_2_Slug,
"Short desc 2"))).Id;
}
private async Task SeedBlogFeaturesAsync()

4
modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs

@ -79,13 +79,13 @@ namespace Volo.CmsKit
public string BlogSlug => "cms-blog";
public Guid BlogPost_1_Id { get; } = Guid.NewGuid();
public Guid BlogPost_1_Id { get; internal set; }
public string BlogPost_1_Title => "How to install CmsKit?";
public string BlogPost_1_Slug => "how-to-install-cms-kit";
public Guid BlogPost_2_Id { get; } = Guid.NewGuid();
public Guid BlogPost_2_Id { get; internal set; }
public string BlogPost_2_Title => "How to use CmsKit";

Loading…
Cancel
Save