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.Contracts/Volo/CmsKit/Admin/Tags/EntityTagSetDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagSetDto.cs new file mode 100644 index 0000000000..d80c1aa62a --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagSetDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Volo.CmsKit.Admin.Tags +{ + public class EntityTagSetDto + { + public string EntityId { get; set; } + public string EntityType { get; set; } + public List Tags { get; set; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/IEntityTagAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/IEntityTagAdminAppService.cs index aece4d5c00..a6660a324f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/IEntityTagAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/IEntityTagAdminAppService.cs @@ -7,5 +7,7 @@ namespace Volo.CmsKit.Admin.Tags Task AddTagToEntityAsync(EntityTagCreateDto input); Task RemoveTagFromEntityAsync(EntityTagRemoveDto input); + + Task SetEntityTagsAsync(EntityTagSetDto input); } } 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.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs index b34e918058..2ad96af963 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs @@ -1,6 +1,14 @@ using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; using Volo.Abp.AutoMapper; +using Volo.Abp.GlobalFeatures; +using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.CmsKit.Blogs; +using Volo.CmsKit.GlobalFeatures; +using Volo.CmsKit.Localization; +using Volo.CmsKit.Permissions; +using Volo.CmsKit.Tags; namespace Volo.CmsKit.Admin { @@ -11,6 +19,11 @@ namespace Volo.CmsKit.Admin )] public class CmsKitAdminApplicationModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + ConfigureTagOptions(); + } + public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAutoMapperObjectMapper(); @@ -20,5 +33,22 @@ namespace Volo.CmsKit.Admin options.AddMaps(validate: true); }); } + + private void ConfigureTagOptions() + { + Configure(opts => + { + if (GlobalFeatureManager.Instance.IsEnabled()) + { + opts.EntityTypes.AddIfNotContains( + new TagEntityTypeDefiniton( + BlogPostConsts.EntityType, + LocalizableString.Create("BlogPost"), + CmsKitAdminPermissions.BlogPosts.Update, + CmsKitAdminPermissions.BlogPosts.Update, + CmsKitAdminPermissions.BlogPosts.Update)); + } + }); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs index 1ef6a8bdf9..b36ffedbd2 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs @@ -1,24 +1,32 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Volo.CmsKit.Admin.Tags; using Volo.CmsKit.Tags; -namespace Volo.CmsKit.Admin.Application.Volo.CmsKit.Admin.Tags +namespace Volo.CmsKit.Admin.Tags { public class EntityTagAdminAppService : CmsKitAdminAppServiceBase, IEntityTagAdminAppService { - protected ITagDefinitionStore _tagDefinitionStore; - protected IEntityTagManager _entityTagManager; - protected ITagManager _tagManager; + protected readonly ITagDefinitionStore _tagDefinitionStore; + protected readonly IEntityTagManager _entityTagManager; + protected readonly ITagManager _tagManager; + protected readonly ITagRepository _tagRepository; + protected readonly IEntityTagRepository _entityTagRepository; public EntityTagAdminAppService( ITagDefinitionStore tagDefinitionStore, IEntityTagManager entityTagManager, - ITagManager tagManager) + ITagManager tagManager, + ITagRepository tagRepository, + IEntityTagRepository entityTagRepository) { _tagDefinitionStore = tagDefinitionStore; _entityTagManager = entityTagManager; _tagManager = tagManager; + _tagRepository = tagRepository; + _entityTagRepository = entityTagRepository; } public async Task AddTagToEntityAsync(EntityTagCreateDto input) @@ -48,5 +56,26 @@ namespace Volo.CmsKit.Admin.Application.Volo.CmsKit.Admin.Tags input.EntityId, CurrentTenant?.Id); } + + public async Task SetEntityTagsAsync(EntityTagSetDto input) + { + var definition = await _tagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType); + + await CheckPolicyAsync(definition.UpdatePolicy); + + var existingTags = await _tagRepository.GetAllRelatedTagsAsync(input.EntityType, input.EntityId, CurrentTenant?.Id); + + var deletedTags = existingTags.Where(x => !input.Tags.Contains(x.Name)).ToList(); + var addedTags = input.Tags.Where(x => !existingTags.Any(a => a.Name == x)); + + await _entityTagRepository.DeleteManyAsync(deletedTags.Select(s => s.Id).ToArray()); + + foreach (var addedTag in addedTags) + { + var tag = await _tagManager.GetOrAddAsync(input.EntityType, addedTag, CurrentTenant?.Id); + + await _entityTagManager.AddTagToEntityAsync(tag.Id, input.EntityType, input.EntityId, CurrentTenant?.Id); + } + } } } 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..e2c2f523b1 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] @@ -68,7 +68,7 @@ namespace Volo.CmsKit.Admin.Blogs Response.Headers.Add("Content-Disposition", $"inline;filename=\"{id}\""); Response.Headers.Add("Accept-Ranges", "bytes"); Response.Headers.Add("Cache-Control", "max-age=120"); - Response.ContentType = "image/*"; + Response.ContentType = "image"; return BlogPostAdminAppService.GetCoverImageAsync(id); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs new file mode 100644 index 0000000000..532fae8554 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs @@ -0,0 +1,42 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.GlobalFeatures; +using Volo.CmsKit.Permissions; + +namespace Volo.CmsKit.Admin.Tags +{ + [RequiresGlobalFeature(typeof(TagsFeature))] + [RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)] + [Area("cms-kit")] + [Route("api/cms-kit-admin/entity-tags")] + public class EntityTagAdminController : CmsKitAdminController, IEntityTagAdminAppService + { + protected IEntityTagAdminAppService EntityTagAdminAppService { get; } + + public EntityTagAdminController(IEntityTagAdminAppService entityTagAdminAppService) + { + EntityTagAdminAppService = entityTagAdminAppService; + } + + [HttpPost] + public Task AddTagToEntityAsync(EntityTagCreateDto input) + { + return EntityTagAdminAppService.AddTagToEntityAsync(input); + } + + [HttpDelete] + public Task RemoveTagFromEntityAsync(EntityTagRemoveDto input) + { + return EntityTagAdminAppService.RemoveTagFromEntityAsync(input); + } + + [HttpPut] + public Task SetEntityTagsAsync(EntityTagSetDto input) + { + return EntityTagAdminAppService.SetEntityTagsAsync(input); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Tags/ITagAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Tags/ITagAppService.cs similarity index 89% rename from modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Tags/ITagAppService.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Tags/ITagAppService.cs index 34d54b9006..5ab01940e1 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Tags/ITagAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Tags/ITagAppService.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; using Volo.Abp.Application.Services; using Volo.CmsKit.Tags; -namespace Volo.CmsKit.Public.Tags +namespace Volo.CmsKit.Tags { public interface ITagAppService : IApplicationService { 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.Public.Application/Volo/CmsKit/Public/Tags/TagAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs similarity index 95% rename from modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Tags/TagAppService.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs index 593f011b02..caa6dc4181 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Tags/TagAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; using Volo.CmsKit.Tags; -namespace Volo.CmsKit.Public.Tags +namespace Volo.CmsKit.Tags { public class TagAppService : CmsKitAppServiceBase, ITagAppService { 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 607effcebd..28ca2d9141 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 @@ -9,5 +9,7 @@ public static int MinUrlSlugLength { get; set; } = 2; public static int MaxShortDescriptionLength { get; set; } = 256; + + public const string EntityType = "BlogPost"; } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json index 118344b626..8b2588a12f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json @@ -5,10 +5,12 @@ "CmsKit:0003": "The entity {0} is not taggable.", "CmsKit:BlogPost:0001": "Same url slug already exists!", "CmsKit:Page:0001": "The given url ({0}) already exists.", + "CmsKit:Tag:0002": "The entity is not taggable!", "CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.", "Comments": "Comments", "Delete": "Delete", "Edit": "Edit", + "LastModification": "Last Modification", "LoginToAddComment": "Login to add comment", "LoginToRate": "Login to rate", "LoginToReply": "Login to reply", @@ -29,6 +31,7 @@ "Permission:TagManagement.Update": "Update", "PickYourReaction": "Pick your reaction", "RatingUndoMessage": "Your rating will be undo.", + "Read": "Read", "Reply": "Reply", "Send": "Send", "Star": "Star", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json index 13d7bc7e37..7d77c0649b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json @@ -5,10 +5,12 @@ "CmsKit:0003": "{0} ögesi etiketlenebilir değil.", "CmsKit:BlogPost:0001": "Aynı url etiketi zaten mevcut.", "CmsKit:Page:0001": "Girilen url ({0}) kullanımdadır.", + "CmsKit:Tag:0002": "Bu öge etiketlenebilir değil.", "CommentAuthorizationExceptionMessage": "Bu yorumları görebilmek için yetki gerekir.", "Comments": "Yorumlar", "Delete": "Sil", "Edit": "Düzenle", + "LastModification": "Son Güncellenme", "LoginToAddComment": "Yorum yapmak için giriş yap", "LoginToRate": "Oylamak için giriş yapın", "LoginToReply": "Cevap vermek için giriş yap", @@ -25,6 +27,7 @@ "Permission:TagManagement.Update": "Etiket Güncelleme", "PickYourReaction": "Tepkinizi seçin", "RatingUndoMessage": "Oylamanız geri alınacak.", + "Read": "Oku", "Reply": "Cevapla", "Send": "Gönder", "Star": "Yıldız", 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 a419802b8e..228d8eccbf 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 @@ -25,7 +25,7 @@ namespace Volo.CmsKit.Blogs { await CheckBlogExistenceAsync(blogPost.BlogId); - await CheckUrlSlugExistenceAsync(blogPost.UrlSlug); + await CheckUrlSlugExistenceAsync(blogPost.BlogId, blogPost.UrlSlug); return await blogPostRepository.InsertAsync(blogPost); } @@ -34,16 +34,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..c3cf64b44c 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,12 @@ 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); + + Task GetCountAsync(Guid blogId, 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 0061e1a397..bbff825189 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 @@ -6,6 +6,7 @@ namespace Volo.CmsKit.Blogs { public interface IBlogRepository : IBasicRepository { + public Task GetByUrlSlugAsync(string urlSlug); Task ExistsAsync(Guid blogId); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs index f2ed160671..6ea4f009a2 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs @@ -13,5 +13,7 @@ namespace Volo.CmsKit.Tags [NotNull] string entityId, [CanBeNull] Guid? tenantId, CancellationToken cancellationToken = default); + + Task DeleteManyAsync(Guid[] tagIds, CancellationToken cancellationToken = default); } } \ No newline at end of file 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..df2893dd1e 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,16 @@ 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; +using Volo.Abp.Domain.Entities; namespace Volo.CmsKit.Blogs { @@ -13,16 +20,47 @@ namespace Volo.CmsKit.Blogs { } - public Task GetByUrlSlugAsync(string urlSlug) + public async Task GetByUrlSlugAsync(Guid blogId, string urlSlug, CancellationToken cancellationToken = default) { - return GetAsync(x => x.UrlSlug.ToLower() == urlSlug); + var dbSet = await GetDbSetAsync(); + + return await dbSet + .Include(i=> i.Creator) + .Where(x => + x.BlogId == blogId && x.UrlSlug.ToLower() == urlSlug) + .FirstOrDefaultAsync(cancellationToken: cancellationToken) + ?? throw new EntityNotFoundException(typeof(BlogPost)); + } + + public async Task GetCountAsync(Guid blogId, CancellationToken cancellationToken = default) + { + return await (await GetQueryableAsync()).CountAsync( + x => x.BlogId == blogId, + cancellationToken); + } + + 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(string slug) + 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 0db324ebcf..1f8fe1184b 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,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using System; +using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -17,5 +18,15 @@ namespace Volo.CmsKit.Blogs { return await (await GetQueryableAsync()).AnyAsync(x => x.Id == blogId); } + + public Task GetByUrlSlugAsync(string urlSlug) + { + return GetAsync(x => x.UrlSlug == urlSlug); + } + + public async Task ExistsAsync(Guid blogId) + { + return await (await GetQueryableAsync()).AnyAsync(x => x.Id == blogId); + } } } 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.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs index a82fb7005a..f1d0119885 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs @@ -1,5 +1,8 @@ using JetBrains.Annotations; +using Nito.Disposables; using System; +using System.Linq; +using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; @@ -14,6 +17,13 @@ namespace Volo.CmsKit.Tags { } + public async Task DeleteManyAsync(Guid[] tagIds, CancellationToken cancellationToken = default) + { + var dbSet = await GetDbSetAsync(); + + dbSet.RemoveRange(dbSet.Where(x => tagIds.Contains(x.TagId))); + } + public Task FindAsync( [NotNull] Guid tagId, [NotNull] string entityId, 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..5c20165d11 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,8 +1,16 @@ -using System; +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 Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Users; namespace Volo.CmsKit.MongoDB.Blogs { @@ -12,16 +20,48 @@ 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, + includeDetails: true, + cancellationToken: cancellationToken); } - public async Task SlugExistsAsync(string slug) + public async Task GetCountAsync(Guid blogId, CancellationToken cancellationToken = default) { - var queryable = await GetQueryableAsync(); + return await AsyncExecuter.CountAsync( + await WithDetailsAsync(), + x => x.BlogId == blogId, + cancellationToken); + } + + 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 WithDetailsAsync(); + + var queryable = blogPostQueryable + .Where(x => x.BlogId == blogId); + + 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 GetMongoQueryableAsync(); - return await AsyncExecuter.AnyAsync(queryable, x => x.UrlSlug.ToLower() == slug); + return await queryable.AnyAsync(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 23e0fe1436..f36ed3a666 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 @@ -19,5 +19,17 @@ namespace Volo.CmsKit.MongoDB.Blogs await GetQueryableAsync(), x => x.Id == blogId); } + + public Task GetByUrlSlugAsync(string urlSlug) + { + return GetAsync(x => x.UrlSlug == urlSlug); + } + + public async Task ExistsAsync(Guid blogId) + { + return await AsyncExecuter.AnyAsync( + await GetQueryableAsync(), + x => x.Id == blogId); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs index 3f9e1814fc..c073f8206f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs @@ -1,5 +1,7 @@ using JetBrains.Annotations; +using MongoDB.Driver; using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.MongoDB; @@ -14,6 +16,13 @@ namespace Volo.CmsKit.MongoDB.Tags { } + public async Task DeleteManyAsync(Guid[] tagIds, CancellationToken cancellationToken = default) + { + var collection = await GetCollectionAsync(); + + await collection.DeleteManyAsync(Builders.Filter.In(x => x.TagId, tagIds)); + } + public Task FindAsync( [NotNull] Guid tagId, [NotNull] string entityId, 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..e6c5af3376 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; + +namespace Volo.CmsKit.Public.Blogs +{ + public interface IBlogPostPublicAppService + { + Task> GetListAsync(string blogUrlSlug, PagedAndSortedResultRequestDto input); + + Task GetAsync(string blogUrlSlug, string blogPostUrlSlug); + + Task GetCoverImageAsync(Guid id); + } +} 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..a6eaa6e96d --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.BlobStoring; +using Volo.Abp.Content; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.Public.Blogs +{ + public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPublicAppService + { + protected IBlogRepository BlogRepository { get; } + + protected IBlobContainer BlobContainer { 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 new PagedResultDto( + await BlogPostRepository.GetCountAsync(blog.Id), + ObjectMapper.Map, List>(blogPosts)); + } + + public async Task GetCoverImageAsync(Guid id) + { + var stream = await BlobContainer.GetAsync(id.ToString()); + + return new RemoteStreamContent(stream); + } + } +} 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/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs new file mode 100644 index 0000000000..091efcf183 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs @@ -0,0 +1,53 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; +using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.GlobalFeatures; +using Volo.CmsKit.Public.Blogs; + +namespace Volo.CmsKit.Public.Blogs +{ + [RequiresGlobalFeature(typeof(BlogsFeature))] + [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] + [Area("cms-kit")] + [Route("api/cms-kit-public/blog-posts")] + public class BlogPostPublicController : CmsKitPublicControllerBase, IBlogPostPublicAppService + { + protected IBlogPostPublicAppService BlogPostPublicAppService { get; } + + public BlogPostPublicController(IBlogPostPublicAppService blogPostPublicAppService) + { + BlogPostPublicAppService = blogPostPublicAppService; + } + + [HttpGet] + public Task GetAsync(string blogUrlSlug, string blogPostUrlSlug) + { + return BlogPostPublicAppService.GetAsync(blogUrlSlug, blogPostUrlSlug); + } + + [HttpGet] + [Route("{id}/cover-image")] + public Task GetCoverImageAsync(Guid id) + { + Response.Headers.Add("Content-Disposition", $"inline;filename=\"{id}\""); + Response.Headers.Add("Accept-Ranges", "bytes"); + Response.Headers.Add("Cache-Control", "max-age=120"); + Response.ContentType = "image"; + + return BlogPostPublicAppService.GetCoverImageAsync(id); + } + + [HttpGet] + public Task> GetListAsync(string blogUrlSlug, PagedAndSortedResultRequestDto input) + { + return BlogPostPublicAppService.GetListAsync(blogUrlSlug, input); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml new file mode 100644 index 0000000000..e03bf06991 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml @@ -0,0 +1,63 @@ +@page "/blogs/{blogUrlSlug}/{blogPostUrlSlug}" + +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPost +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPostComment +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs +@using Volo.CmsKit.Public.Web.Pages +@using Volo.Abp.GlobalFeatures +@using Volo.CmsKit.GlobalFeatures +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelection +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Tags + +@inherits CmsKitPublicPageBase + +@model BlogPostModel + +@{ + PageLayout.Content.Title = Model.BlogPost.Title; +} + +@await Component.InvokeAsync(typeof(DefaultBlogPostViewComponent), new +{ + Model.BlogUrlSlug, + Model.BlogPostUrlSlug +}) + +@if (GlobalFeatureManager.Instance.IsEnabled()) +{ + @await Component.InvokeAsync(typeof(TagViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) +} + +@if (GlobalFeatureManager.Instance.IsEnabled()) +{ + @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) +} + +@if (GlobalFeatureManager.Instance.IsEnabled()) +{ + @await Component.InvokeAsync(typeof(RatingViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) +} + +
+ +@if (GlobalFeatureManager.Instance.IsEnabled()) +{ + @await Component.InvokeAsync(typeof(DefaultBlogPostCommentViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs new file mode 100644 index 0000000000..4a63ec1692 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.CmsKit.Public.Blogs; + +namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs +{ + public class BlogPostModel : CmsKitPublicPageModelBase + { + [BindProperty(SupportsGet = true)] + public string BlogUrlSlug { get; set; } + + [BindProperty(SupportsGet = true)] + public string BlogPostUrlSlug { get; set; } + + public BlogPostPublicDto BlogPost { get; private set; } + + protected IBlogPostPublicAppService BlogPostPublicAppService { get; } + + public BlogPostModel(IBlogPostPublicAppService blogPostPublicAppService) + { + BlogPostPublicAppService = blogPostPublicAppService; + } + + public async Task OnGetAsync() + { + BlogPost = await BlogPostPublicAppService.GetAsync(BlogUrlSlug, BlogPostUrlSlug); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml new file mode 100644 index 0000000000..7a3660dbf5 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml @@ -0,0 +1,47 @@ +@page "/blogs/{blogUrlSlug}" + +@using Volo.CmsKit.Public.Web.Pages + +@inherits CmsKitPublicPageBase + +@model Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs.IndexModel + + + @foreach (var blog in Model.Blogs.Items) + { + + + + + @blog.Title + + + @@@blog.Creator?.UserName + + + + + + @blog.ShortDescription + + + + + + + + + + @blog.CreationTime + + + + + + } + + + + + diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml.cs new file mode 100644 index 0000000000..d375efef61 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml.cs @@ -0,0 +1,45 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination; +using Volo.CmsKit.Public.Blogs; + +namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs +{ + public class IndexModel : CmsKitPublicPageModelBase + { + public const int PageSize = 12; + + [BindProperty(SupportsGet = true)] + public string BlogUrlSlug { get; set; } + + [BindProperty(SupportsGet = true)] + public int CurrentPage { get; set; } = 1; + + public PagedResultDto Blogs { get; private set; } + + public PagerModel PagerModel => new PagerModel(Blogs.TotalCount, Blogs.Items.Count, CurrentPage, PageSize, Request.Path.ToString()); + + protected IBlogPostPublicAppService BlogPostPublicAppService { get; } + + public IndexModel(IBlogPostPublicAppService blogPostPublicAppService) + { + BlogPostPublicAppService = blogPostPublicAppService; + } + + public async Task OnGetAsync() + { + Blogs = await BlogPostPublicAppService.GetListAsync( + BlogUrlSlug, + new PagedAndSortedResultRequestDto + { + SkipCount = PageSize * (CurrentPage - 1), + MaxResultCount = PageSize + }); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml new file mode 100644 index 0000000000..ebb009448d --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml @@ -0,0 +1,33 @@ +@model Volo.CmsKit.Public.Blogs.BlogPostPublicDto +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents +@using Volo.Abp.AspNetCore.Mvc.UI.Layout +@using Volo.CmsKit.Localization +@using Microsoft.Extensions.Localization + +@inject IStringLocalizer L + + + + + @Model.Title + @@@Model.Creator?.UserName + + + + + @await Component.InvokeAsync(typeof(ContentViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.Id.ToString() + }) + + + @Model.CreationTime + @if (Model.LastModificationTime != null) + { + @L["LastModification"].Value : @Model.LastModificationTime + } + + + + diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/DefaultBlogPostViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/DefaultBlogPostViewComponent.cs new file mode 100644 index 0000000000..4a055d6679 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/DefaultBlogPostViewComponent.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc; +using Volo.CmsKit.Public.Blogs; + +namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPost +{ + [ViewComponent(Name = "CmsDefaultBlogPost")] + public class DefaultBlogPostViewComponent : AbpViewComponent + { + protected IBlogPostPublicAppService BlogPostPublicAppService { get; } + + public DefaultBlogPostViewComponent(IBlogPostPublicAppService blogPostPublicAppService) + { + BlogPostPublicAppService = blogPostPublicAppService; + } + + public virtual async Task InvokeAsync(string blogUrlSlug, string blogPostUrlSlug) + { + var blogPost = await BlogPostPublicAppService.GetAsync(blogUrlSlug, blogPostUrlSlug); + + return View("~/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml", blogPost); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml new file mode 100644 index 0000000000..c34f64eb0c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml @@ -0,0 +1,22 @@ +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPostComment +@using Volo.CmsKit.Localization +@using Microsoft.Extensions.Localization + +@inject IStringLocalizer L + +@model DefaultBlogPostCommentViewComponent.DefaultBlogPostCommentViewModel + + + + + @L["Comments"] + + + @await Component.InvokeAsync(typeof(CommentingViewComponent), new + { + entityType = Model.EntityType, + entityId = Model.EntityId + }) + + \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/DefaultBlogPostCommentViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/DefaultBlogPostCommentViewComponent.cs new file mode 100644 index 0000000000..c551146f5f --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/DefaultBlogPostCommentViewComponent.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc; +using Volo.CmsKit.Public.Blogs; + +namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPostComment +{ + [ViewComponent(Name = "CmsDefaultBlogPostComment")] + public class DefaultBlogPostCommentViewComponent : AbpViewComponent + { + protected IBlogPostPublicAppService BlogPostPublicAppService; + + public DefaultBlogPostCommentViewComponent(IBlogPostPublicAppService blogPostPublicAppService) + { + BlogPostPublicAppService = blogPostPublicAppService; + } + + public virtual async Task InvokeAsync(string entityType, string entityId) + { + return View( + "~/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml", + new DefaultBlogPostCommentViewModel + { + EntityType = entityType, + EntityId = entityId + }); + } + + public class DefaultBlogPostCommentViewModel + { + public string EntityType { get; set; } + public string EntityId { get; set; } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPublicPageBase.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPublicPageBase.cs new file mode 100644 index 0000000000..879745bf24 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPublicPageBase.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Mvc.Razor.Internal; +using Microsoft.Extensions.Localization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc.UI.Layout; +using Volo.CmsKit.Localization; + +namespace Volo.CmsKit.Public.Web.Pages +{ + public class CmsKitPublicPageBase : Microsoft.AspNetCore.Mvc.RazorPages.Page + { + [RazorInject] + public IStringLocalizer L { get; set; } + + [RazorInject] + public IPageLayout PageLayout { get; set; } + + public override Task ExecuteAsync() + { + return Task.CompletedTask; // Will be overriden by razor pages. (.cshtml) + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Properties/launchSettings.json b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Properties/launchSettings.json new file mode 100644 index 0000000000..60e2c66615 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:60873/", + "sslPort": 44300 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Volo.CmsKit.Public.Web": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + } + } +} \ No newline at end of file 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.Application.Tests/Tags/TagPublicAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagPublicAppService_Tests.cs index 50eefd186b..26a7454a2b 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagPublicAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagPublicAppService_Tests.cs @@ -3,7 +3,7 @@ using NSubstitute; using Shouldly; using System.Threading.Tasks; using Volo.Abp.Users; -using Volo.CmsKit.Public.Tags; +using Volo.CmsKit.Tags; using Xunit; namespace Volo.CmsKit.Tags 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 bd5f553367..3fac76bfd9 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,10 +5,6 @@ Volo.CmsKit - - - - 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.EntityFrameworkCore.Tests/EntityFrameworkCore/Tags/EntityTagRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Tags/EntityTagRepository_Test.cs new file mode 100644 index 0000000000..01464f46e8 --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Tags/EntityTagRepository_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.Tags; + +namespace Volo.CmsKit.EntityFrameworkCore.Tags +{ + public class EntityTagRepository_Test : EntityTagRepository_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.MongoDB.Tests/MongoDB/Tags/EntityTagRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Tags/EntityTagRepository_Test.cs new file mode 100644 index 0000000000..919455b109 --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Tags/EntityTagRepository_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.Tags; +using Xunit; + +namespace Volo.CmsKit.MongoDB.Tags +{ + [Collection(MongoTestCollection.Name)] + public class EntityTagRepository_Test : EntityTagRepository_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..5119dfd75b --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs @@ -0,0 +1,65 @@ +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)); + } + + [Fact] + public async Task ExistsAsync_ShouldReturnTrue_WithExistingId() + { + var result = await blogRepository.ExistsAsync(testData.Blog_Id); + + result.ShouldBeTrue(); + } + + [Fact] + public async Task ExistsAsync_ShouldReturnFalse_WithExistingId() + { + var nonExistingId = Guid.NewGuid(); + + var result = await blogRepository.ExistsAsync(nonExistingId); + + result.ShouldBeFalse(); + } + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/EntityTagRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/EntityTagRepository_Test.cs new file mode 100644 index 0000000000..3d60ac0b6a --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/EntityTagRepository_Test.cs @@ -0,0 +1,38 @@ +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Modularity; +using Xunit; + +namespace Volo.CmsKit.Tags +{ + public abstract class EntityTagRepository_Test : CmsKitTestBase + where TStartupModule : IAbpModule + { + private CmsKitTestData _cmsKitTestData; + private IEntityTagRepository _entityTagRepository; + private ITagRepository _tagRepository; + + public EntityTagRepository_Test() + { + _cmsKitTestData = GetRequiredService(); + _entityTagRepository = GetRequiredService(); + _tagRepository = GetRequiredService(); + } + + [Fact] + public async Task DeleteManyAsync_ShouldWorkProperly_WithExistingIds() + { + var relatedTags = await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_EntityId); + + await _entityTagRepository.DeleteManyAsync(relatedTags.Select(s => s.Id).ToArray()); + + relatedTags = await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_EntityId); + + relatedTags.ShouldBeEmpty(); + } + } +}