Browse Source

CmsKit - Merge BlogPost Public into initial

pull/7226/head
enisn 6 years ago
parent
commit
d1eb33a92d
  1. 8
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs
  2. 15
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagSetDto.cs
  3. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/IEntityTagAdminAppService.cs
  4. 9
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs
  5. 30
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs
  6. 39
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs
  7. 8
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs
  8. 42
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs
  9. 2
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Tags/ITagAppService.cs
  10. 20
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Users/CmsUserDto.cs
  11. 3
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationAutoMapperProfile.cs
  12. 2
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs
  13. 2
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs
  14. 3
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json
  15. 3
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json
  16. 2
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs
  17. 2
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs
  18. 10
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs
  19. 10
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostUrlSlugAlreadyExistException.cs
  20. 9
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs
  21. 1
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs
  22. 2
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs
  23. 46
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs
  24. 11
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs
  25. 2
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs
  26. 10
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs
  27. 52
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs
  28. 12
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs
  29. 9
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs
  30. 17
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs
  31. 17
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs
  32. 54
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs
  33. 6
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs
  34. 53
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs
  35. 63
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml
  36. 33
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs
  37. 47
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml
  38. 45
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml.cs
  39. 33
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml
  40. 29
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/DefaultBlogPostViewComponent.cs
  41. 22
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml
  42. 39
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/DefaultBlogPostCommentViewComponent.cs
  43. 26
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPublicPageBase.cs
  44. 27
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Properties/launchSettings.json
  45. 16
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs
  46. 2
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagPublicAppService_Tests.cs
  47. 4
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Volo.CmsKit.Application.Tests.csproj
  48. 14
      modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogPostRepository_Test.cs
  49. 14
      modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogRepository_Test.cs
  50. 14
      modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Tags/EntityTagRepository_Test.cs
  51. 16
      modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogPostRepository_Test.cs
  52. 16
      modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogRepository_Test.cs
  53. 16
      modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Tags/EntityTagRepository_Test.cs
  54. 125
      modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs
  55. 65
      modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs
  56. 38
      modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/EntityTagRepository_Test.cs

8
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<BlogPostDto> GetByUrlSlugAsync(string urlSlug);
Task<BlogPostDto> GetByUrlSlugAsync(string blogUrlSlug, string urlSlug);
Task SetCoverImageAsync(Guid id, RemoteStreamContent streamContent);

15
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<string> Tags { get; set; }
}
}

2
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);
}
}

9
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<BlogPostCoverImageContainer> BlobContainer;
protected readonly ICmsUserLookupService UserLookupService;
@ -35,11 +36,13 @@ namespace Volo.CmsKit.Admin.Blogs
IRepository<BlogPost, Guid> repository,
IBlogPostManager blogPostManager,
IBlogPostRepository blogPostRepository,
IBlogRepository blogRepository,
IBlobContainer<BlogPostCoverImageContainer> 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<BlogPostDto> GetByUrlSlugAsync(string urlSlug)
public virtual async Task<BlogPostDto> 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);
}

30
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<CmsKitAdminApplicationModule>();
@ -20,5 +33,22 @@ namespace Volo.CmsKit.Admin
options.AddMaps<CmsKitAdminApplicationModule>(validate: true);
});
}
private void ConfigureTagOptions()
{
Configure<CmsKitTagOptions>(opts =>
{
if (GlobalFeatureManager.Instance.IsEnabled<BlogsFeature>())
{
opts.EntityTypes.AddIfNotContains(
new TagEntityTypeDefiniton(
BlogPostConsts.EntityType,
LocalizableString.Create<CmsKitResource>("BlogPost"),
CmsKitAdminPermissions.BlogPosts.Update,
CmsKitAdminPermissions.BlogPosts.Update,
CmsKitAdminPermissions.BlogPosts.Update));
}
});
}
}
}

39
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);
}
}
}
}

8
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<BlogPostDto> GetByUrlSlugAsync(string urlSlug)
public virtual Task<BlogPostDto> 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);
}

42
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);
}
}
}

2
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Tags/ITagAppService.cs → 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
{

20
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<Guid>
{
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; }
}
}

3
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<Tag, TagDto>();
CreateMap<CmsUser, CmsUserDto>();
}
}
}

2
modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Tags/TagAppService.cs → 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
{

2
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";
}
}

3
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",

3
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",

2
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)
{

2
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()
{

10
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);
}
}

10
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; }
}
}

9
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<BlogPost, Guid>
{
Task<bool> SlugExistsAsync(string slug);
Task<bool> SlugExistsAsync(Guid blogId, string slug, CancellationToken cancellationToken = default);
Task<BlogPost> GetByUrlSlugAsync(string urlSlug);
Task<BlogPost> GetByUrlSlugAsync(Guid blogId, string urlSlug, CancellationToken cancellationToken = default);
Task<List<BlogPost>> GetPagedListAsync(Guid blogId, int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default);
Task<int> GetCountAsync(Guid blogId, CancellationToken cancellationToken = default);
}
}

1
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs

@ -6,6 +6,7 @@ namespace Volo.CmsKit.Blogs
{
public interface IBlogRepository : IBasicRepository<Blog, Guid>
{
public Task<Blog> GetByUrlSlugAsync(string urlSlug);
Task<bool> ExistsAsync(Guid blogId);
}
}

2
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);
}
}

46
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<BlogPost> GetByUrlSlugAsync(string urlSlug)
public async Task<BlogPost> 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<int> GetCountAsync(Guid blogId, CancellationToken cancellationToken = default)
{
return await (await GetQueryableAsync()).CountAsync(
x => x.BlogId == blogId,
cancellationToken);
}
public async Task<List<BlogPost>> 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<bool> SlugExistsAsync(string slug)
public async Task<bool> 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);
}
}
}

11
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<Blog> GetByUrlSlugAsync(string urlSlug)
{
return GetAsync(x => x.UrlSlug == urlSlug);
}
public async Task<bool> ExistsAsync(Guid blogId)
{
return await (await GetQueryableAsync()).AnyAsync(x => x.Id == blogId);
}
}
}

2
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

10
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<EntityTag> FindAsync(
[NotNull] Guid tagId,
[NotNull] string entityId,

52
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<BlogPost> GetByUrlSlugAsync(string urlSlug)
public Task<BlogPost> 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<bool> SlugExistsAsync(string slug)
public async Task<int> GetCountAsync(Guid blogId, CancellationToken cancellationToken = default)
{
var queryable = await GetQueryableAsync();
return await AsyncExecuter.CountAsync(
await WithDetailsAsync(),
x => x.BlogId == blogId,
cancellationToken);
}
public async Task<List<BlogPost>> 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<bool> 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);
}
}
}

12
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<Blog> GetByUrlSlugAsync(string urlSlug)
{
return GetAsync(x => x.UrlSlug == urlSlug);
}
public async Task<bool> ExistsAsync(Guid blogId)
{
return await AsyncExecuter.AnyAsync(
await GetQueryableAsync(),
x => x.Id == blogId);
}
}
}

9
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<EntityTag>.Filter.In(x => x.TagId, tagIds));
}
public Task<EntityTag> FindAsync(
[NotNull] Guid tagId,
[NotNull] string entityId,

17
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<Guid, CmsUserDto>
{
public Guid BlogId { get; set; }
public string Title { get; set; }
public string UrlSlug { get; set; }
public string ShortDescription { get; set; }
}
}

17
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<PagedResultDto<BlogPostPublicDto>> GetListAsync(string blogUrlSlug, PagedAndSortedResultRequestDto input);
Task<BlogPostPublicDto> GetAsync(string blogUrlSlug, string blogPostUrlSlug);
Task<RemoteStreamContent> GetCoverImageAsync(Guid id);
}
}

54
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<BlogPostCoverImageContainer> BlobContainer { get; }
protected IBlogPostRepository BlogPostRepository { get; }
public BlogPostPublicAppService(
IBlogRepository blogRepository,
IBlogPostRepository blogPostRepository)
{
BlogRepository = blogRepository;
BlogPostRepository = blogPostRepository;
}
public async Task<BlogPostPublicDto> GetAsync(string blogUrlSlug, string blogPostUrlSlug)
{
var blog = await BlogRepository.GetByUrlSlugAsync(blogUrlSlug);
var blogPost = await BlogPostRepository.GetByUrlSlugAsync(blog.Id, blogPostUrlSlug);
return ObjectMapper.Map<BlogPost, BlogPostPublicDto>(blogPost);
}
public async Task<PagedResultDto<BlogPostPublicDto>> 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<BlogPostPublicDto>(
await BlogPostRepository.GetCountAsync(blog.Id),
ObjectMapper.Map<List<BlogPost>, List<BlogPostPublicDto>>(blogPosts));
}
public async Task<RemoteStreamContent> GetCoverImageAsync(Guid id)
{
var stream = await BlobContainer.GetAsync(id.ToString());
return new RemoteStreamContent(stream);
}
}
}

6
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<CmsUser, CmsUserDto>();
CreateMap<CmsUser, Comments.CmsUserDto>();
CreateMap<Comment, CommentDto>()
.Ignore(x=> x.Author);
@ -30,6 +32,8 @@ namespace Volo.CmsKit.Public
CreateMap<Content, ContentDto>();
CreateMap<Page, PageDto>();
CreateMap<BlogPost, BlogPostPublicDto>(MemberList.None);
}
}
}

53
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<BlogPostPublicDto> GetAsync(string blogUrlSlug, string blogPostUrlSlug)
{
return BlogPostPublicAppService.GetAsync(blogUrlSlug, blogPostUrlSlug);
}
[HttpGet]
[Route("{id}/cover-image")]
public Task<RemoteStreamContent> 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<PagedResultDto<BlogPostPublicDto>> GetListAsync(string blogUrlSlug, PagedAndSortedResultRequestDto input)
{
return BlogPostPublicAppService.GetListAsync(blogUrlSlug, input);
}
}
}

63
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<TagsFeature>())
{
@await Component.InvokeAsync(typeof(TagViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}
@if (GlobalFeatureManager.Instance.IsEnabled<ReactionsFeature>())
{
@await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}
@if (GlobalFeatureManager.Instance.IsEnabled<RatingsFeature>())
{
@await Component.InvokeAsync(typeof(RatingViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}
<hr />
@if (GlobalFeatureManager.Instance.IsEnabled<CommentsFeature>())
{
@await Component.InvokeAsync(typeof(DefaultBlogPostCommentViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}

33
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);
}
}
}

47
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
<abp-row id="blogs-container">
@foreach (var blog in Model.Blogs.Items)
{
<abp-column size="_12" class="m-3">
<abp-card>
<abp-card-header>
<abp-card-title>
@blog.Title
</abp-card-title>
<abp-card-subtitle>
@@@blog.Creator?.UserName
</abp-card-subtitle>
</abp-card-header>
<abp-card-body>
<img src="/api/cms-kit-public/blog-posts/@blog.Id/cover-image" class="card-img-top" onerror="this.src='https://dummyimage.com/300x200/a3a3a3/fff.png'"/>
<abp-card-text>
@blog.ShortDescription
</abp-card-text>
<abp-card-text>
<a href="/blogs/@Model.BlogUrlSlug/@blog.UrlSlug">
<abp-button text="@L["Read"]"
button-type="Outline_Primary" />
</a>
</abp-card-text>
</abp-card-body>
<abp-card-footer>
<abp-card-text>
@blog.CreationTime
</abp-card-text>
</abp-card-footer>
</abp-card>
</abp-column>
}
</abp-row>
<abp-row>
<abp-paginator model="Model.PagerModel" />
</abp-row>

45
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<BlogPostPublicDto> 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
});
}
}
}

33
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<CmsKitResource> L
<abp-card>
<abp-card-header>
<abp-card-title>@Model.Title</abp-card-title>
<abp-card-subtitle>@@@Model.Creator?.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" onerror="this.src='https://dummyimage.com/300x200/a3a3a3/fff.png'" />
@await Component.InvokeAsync(typeof(ContentViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.Id.ToString()
})
</abp-card-body>
<abp-card-footer>
<abp-card-subtitle>@Model.CreationTime</abp-card-subtitle>
@if (Model.LastModificationTime != null)
{
<abp-card-text><i>@L["LastModification"].Value : @Model.LastModificationTime</i></abp-card-text>
}
</abp-card-footer>
</abp-card>

29
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<IViewComponentResult> InvokeAsync(string blogUrlSlug, string blogPostUrlSlug)
{
var blogPost = await BlogPostPublicAppService.GetAsync(blogUrlSlug, blogPostUrlSlug);
return View("~/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml", blogPost);
}
}
}

22
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<CmsKitResource> L
@model DefaultBlogPostCommentViewComponent.DefaultBlogPostCommentViewModel
<abp-card>
<abp-card-header>
<abp-card-title>@L["Comments"]</abp-card-title>
</abp-card-header>
<abp-card-body>
@await Component.InvokeAsync(typeof(CommentingViewComponent), new
{
entityType = Model.EntityType,
entityId = Model.EntityId
})
</abp-card-body>
</abp-card>

39
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<IViewComponentResult> 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; }
}
}
}

26
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<CmsKitResource> L { get; set; }
[RazorInject]
public IPageLayout PageLayout { get; set; }
public override Task ExecuteAsync()
{
return Task.CompletedTask; // Will be overriden by razor pages. (.cshtml)
}
}
}

27
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"
}
}
}

16
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<EntityNotFoundException>(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<EntityNotFoundException>(async () =>
await blogPostAdminAppService.GetByUrlSlugAsync(nonExistingUrlSlug, cmsKitTestData.Page_1_Url));
exception.EntityType.ShouldBe(typeof(Blog));
}
[Fact]
public async Task GetListAsync_ShouldWorkProperly_WithDefaultParameters()
{

2
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

4
modules/cms-kit/test/Volo.CmsKit.Application.Tests/Volo.CmsKit.Application.Tests.csproj

@ -5,10 +5,6 @@
<RootNamespace>Volo.CmsKit</RootNamespace>
</PropertyGroup>
<ItemGroup>
<None Remove="Data\BlogPostSample.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Data\**\*" />
</ItemGroup>

14
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<CmsKitEntityFrameworkCoreTestModule>
{
}
}

14
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<CmsKitEntityFrameworkCoreTestModule>
{
}
}

14
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<CmsKitEntityFrameworkCoreTestModule>
{
}
}

16
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<CmsKitMongoDbTestModule>
{
}
}

16
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<CmsKitMongoDbTestModule>
{
}
}

16
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<CmsKitMongoDbTestModule>
{
}
}

125
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<TStartupModule> : CmsKitTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly CmsKitTestData testData;
private readonly IBlogPostRepository blogPostRepository;
public BlogPostRepository_Test()
{
testData = GetRequiredService<CmsKitTestData>();
blogPostRepository = GetRequiredService<IBlogPostRepository>();
}
[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<EntityNotFoundException>(
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<EntityNotFoundException>(
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);
}
}
}

65
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<TStartupModule> : CmsKitTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly CmsKitTestData testData;
private readonly IBlogRepository blogRepository;
public BlogRepository_Test()
{
this.testData = GetRequiredService<CmsKitTestData>();
this.blogRepository = GetRequiredService<IBlogRepository>();
}
[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<EntityNotFoundException>(
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();
}
}
}

38
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<TStartupModule> : CmsKitTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private CmsKitTestData _cmsKitTestData;
private IEntityTagRepository _entityTagRepository;
private ITagRepository _tagRepository;
public EntityTagRepository_Test()
{
_cmsKitTestData = GetRequiredService<CmsKitTestData>();
_entityTagRepository = GetRequiredService<IEntityTagRepository>();
_tagRepository = GetRequiredService<ITagRepository>();
}
[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();
}
}
}
Loading…
Cancel
Save