mirror of https://github.com/abpframework/abp.git
committed by
GitHub
103 changed files with 4874 additions and 90 deletions
File diff suppressed because it is too large
@ -0,0 +1,106 @@ |
|||
using System; |
|||
using Microsoft.EntityFrameworkCore.Migrations; |
|||
|
|||
namespace Volo.CmsKit.Migrations |
|||
{ |
|||
public partial class UrlSlugToSlug : Migration |
|||
{ |
|||
protected override void Up(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.CreateTable( |
|||
name: "CmsBlogPosts", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), |
|||
BlogId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), |
|||
Title = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false), |
|||
Slug = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false), |
|||
ShortDescription = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), |
|||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
|||
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true), |
|||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true), |
|||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), |
|||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
|||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), |
|||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
|||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false), |
|||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
|||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true) |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_CmsBlogPosts", x => x.Id); |
|||
table.ForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_CreatorId", |
|||
column: x => x.CreatorId, |
|||
principalTable: "CmsUsers", |
|||
principalColumn: "Id", |
|||
onDelete: ReferentialAction.Restrict); |
|||
table.ForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_DeleterId", |
|||
column: x => x.DeleterId, |
|||
principalTable: "CmsUsers", |
|||
principalColumn: "Id", |
|||
onDelete: ReferentialAction.Restrict); |
|||
table.ForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_LastModifierId", |
|||
column: x => x.LastModifierId, |
|||
principalTable: "CmsUsers", |
|||
principalColumn: "Id", |
|||
onDelete: ReferentialAction.Restrict); |
|||
}); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "CmsBlogs", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), |
|||
Name = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false), |
|||
Slug = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false), |
|||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
|||
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true), |
|||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true), |
|||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), |
|||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
|||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), |
|||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
|||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false), |
|||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
|||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true) |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_CmsBlogs", x => x.Id); |
|||
}); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_CmsBlogPosts_CreatorId", |
|||
table: "CmsBlogPosts", |
|||
column: "CreatorId"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_CmsBlogPosts_DeleterId", |
|||
table: "CmsBlogPosts", |
|||
column: "DeleterId"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_CmsBlogPosts_LastModifierId", |
|||
table: "CmsBlogPosts", |
|||
column: "LastModifierId"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_CmsBlogPosts_Slug_BlogId", |
|||
table: "CmsBlogPosts", |
|||
columns: new[] { "Slug", "BlogId" }); |
|||
} |
|||
|
|||
protected override void Down(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.DropTable( |
|||
name: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "CmsBlogs"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Blogs; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
public class BlogDto : EntityDto<Guid> |
|||
{ |
|||
[Required] |
|||
[DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))] |
|||
public string Name { get; set; } |
|||
|
|||
[Required] |
|||
[DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxSlugLength))] |
|||
public string Slug { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
public class BlogGetListInput : PagedAndSortedResultRequestDto |
|||
{ |
|||
public string Filter { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
public class BlogLookupDto |
|||
{ |
|||
public Guid Id { get; set; } |
|||
public string Name { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System; |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
public class BlogPostDto : EntityDto<Guid> |
|||
{ |
|||
public Guid BlogId { get; set; } |
|||
|
|||
public string Title { get; set; } |
|||
|
|||
public string Slug { get; set; } |
|||
public string ShortDescription { get; protected set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Blogs; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
public class CreateUpdateBlogPostDto |
|||
{ |
|||
[Required] |
|||
public Guid BlogId { get; set; } |
|||
|
|||
[Required] |
|||
[DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxTitleLength))] |
|||
public string Title { get; set; } |
|||
|
|||
[Required] |
|||
[DynamicStringLength( |
|||
typeof(BlogPostConsts), |
|||
nameof(BlogPostConsts.MaxSlugLength), |
|||
nameof(BlogPostConsts.MinSlugLength))] |
|||
public string Slug { get; set; } |
|||
|
|||
[DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxShortDescriptionLength))] |
|||
public string ShortDescription { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
public interface IBlogAdminAppService : ICrudAppService<BlogDto, Guid, BlogGetListInput> |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.Content; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
public interface IBlogPostAdminAppService |
|||
: ICrudAppService< |
|||
BlogPostDto, |
|||
Guid, |
|||
PagedAndSortedResultRequestDto, |
|||
CreateUpdateBlogPostDto> |
|||
{ |
|||
Task<BlogPostDto> GetBySlugAsync(string blogSlug, string slug); |
|||
|
|||
Task SetCoverImageAsync(Guid id, RemoteStreamContent streamContent); |
|||
|
|||
Task<RemoteStreamContent> GetCoverImageAsync(Guid id); |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.Domain.Repositories; |
|||
using Volo.Abp.GlobalFeatures; |
|||
using Volo.CmsKit.Blogs; |
|||
using Volo.CmsKit.GlobalFeatures; |
|||
using Volo.CmsKit.Permissions; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
[RequiresGlobalFeature(typeof(BlogsFeature))] |
|||
[Authorize(CmsKitAdminPermissions.Blogs.Default)] |
|||
public class BlogAdminAppService : CrudAppService<Blog, BlogDto, Guid, BlogGetListInput>, IBlogAdminAppService |
|||
{ |
|||
public BlogAdminAppService(IRepository<Blog, Guid> repository) : base(repository) |
|||
{ |
|||
GetListPolicyName = CmsKitAdminPermissions.Blogs.Default; |
|||
GetPolicyName = CmsKitAdminPermissions.Blogs.Default; |
|||
CreatePolicyName = CmsKitAdminPermissions.Blogs.Create; |
|||
UpdatePolicyName = CmsKitAdminPermissions.Blogs.Update; |
|||
DeletePolicyName = CmsKitAdminPermissions.Blogs.Delete; |
|||
} |
|||
|
|||
protected override async Task<IQueryable<Blog>> CreateFilteredQueryAsync(BlogGetListInput input) |
|||
{ |
|||
var queryable = await base.CreateFilteredQueryAsync(input); |
|||
return queryable |
|||
.WhereIf( |
|||
!input.Filter.IsNullOrWhiteSpace(), |
|||
x => x.Name.ToLower().Contains(input.Filter)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,118 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.Content; |
|||
using Volo.Abp.Domain.Repositories; |
|||
using Volo.Abp.GlobalFeatures; |
|||
using Volo.Abp.Users; |
|||
using Volo.CmsKit.Blogs; |
|||
using Volo.CmsKit.GlobalFeatures; |
|||
using Volo.CmsKit.Permissions; |
|||
using Volo.CmsKit.Users; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
[RequiresGlobalFeature(typeof(BlogsFeature))] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)] |
|||
public class BlogPostAdminAppService |
|||
: CrudAppService< |
|||
BlogPost, |
|||
BlogPostDto, |
|||
Guid, |
|||
PagedAndSortedResultRequestDto, |
|||
CreateUpdateBlogPostDto> |
|||
, IBlogPostAdminAppService |
|||
{ |
|||
protected readonly IBlogPostManager BlogPostManager; |
|||
protected readonly IBlogPostRepository BlogPostRepository; |
|||
protected readonly IBlogRepository BlogRepository; |
|||
protected readonly IBlobContainer<BlogPostCoverImageContainer> BlobContainer; |
|||
protected readonly ICmsUserLookupService UserLookupService; |
|||
|
|||
public BlogPostAdminAppService( |
|||
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; |
|||
|
|||
GetListPolicyName = CmsKitAdminPermissions.BlogPosts.Default; |
|||
GetPolicyName = CmsKitAdminPermissions.BlogPosts.Default; |
|||
CreatePolicyName = CmsKitAdminPermissions.BlogPosts.Create; |
|||
UpdatePolicyName = CmsKitAdminPermissions.BlogPosts.Update; |
|||
DeletePolicyName = CmsKitAdminPermissions.BlogPosts.Delete; |
|||
} |
|||
|
|||
public virtual async Task<BlogPostDto> GetBySlugAsync(string blogSlug, string blogPostSlug) |
|||
{ |
|||
var blog = await BlogRepository.GetBySlugAsync(blogSlug); |
|||
|
|||
var blogPost = await BlogPostRepository.GetBySlugAsync(blog.Id, blogPostSlug); |
|||
|
|||
return MapToGetOutputDto(blogPost); |
|||
} |
|||
|
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)] |
|||
public override async Task<BlogPostDto> CreateAsync(CreateUpdateBlogPostDto input) |
|||
{ |
|||
_ = await UserLookupService.GetByIdAsync(CurrentUser.GetId()); |
|||
|
|||
var entity = await BlogPostManager |
|||
.CreateAsync( |
|||
new BlogPost( |
|||
GuidGenerator.Create(), |
|||
input.BlogId, |
|||
input.Title, |
|||
input.Slug, |
|||
input.ShortDescription)); |
|||
|
|||
return MapToGetOutputDto(entity); |
|||
} |
|||
|
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Update)] |
|||
public override async Task<BlogPostDto> UpdateAsync(Guid id, CreateUpdateBlogPostDto input) |
|||
{ |
|||
var blogPost = await BlogPostRepository.GetAsync(id); |
|||
|
|||
blogPost.SetTitle(input.Title); |
|||
|
|||
if (blogPost.Slug != input.Slug) |
|||
{ |
|||
await BlogPostManager.SetSlugUrlAsync(blogPost, input.Slug); |
|||
} |
|||
|
|||
MapToEntity(input, blogPost); |
|||
|
|||
await BlogPostManager.UpdateAsync(blogPost); |
|||
|
|||
return MapToGetOutputDto(blogPost); |
|||
} |
|||
|
|||
public virtual async Task SetCoverImageAsync(Guid id, RemoteStreamContent streamContent) |
|||
{ |
|||
await Repository.GetAsync(id); |
|||
|
|||
using (var stream = streamContent.GetStream()) |
|||
{ |
|||
await BlobContainer.SaveAsync(id.ToString(), stream, overrideExisting: true); |
|||
} |
|||
} |
|||
|
|||
public virtual async Task<RemoteStreamContent> GetCoverImageAsync(Guid id) |
|||
{ |
|||
var stream = await BlobContainer.GetAsync(id.ToString()); |
|||
|
|||
return new RemoteStreamContent(stream); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
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.GlobalFeatures; |
|||
using Volo.CmsKit.GlobalFeatures; |
|||
using Volo.CmsKit.Permissions; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
[RequiresGlobalFeature(typeof(BlogsFeature))] |
|||
[RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)] |
|||
[Area("cms-kit")] |
|||
[Authorize(CmsKitAdminPermissions.Blogs.Default)] |
|||
[Route("api/cms-kit-admin/blogs/blogs")] |
|||
public class BlogAdminController : CmsKitAdminController, IBlogAdminAppService |
|||
{ |
|||
protected IBlogAdminAppService BlogAdminAppService { get; } |
|||
|
|||
public BlogAdminController(IBlogAdminAppService blogAdminAppService) |
|||
{ |
|||
BlogAdminAppService = blogAdminAppService; |
|||
} |
|||
|
|||
[HttpPost] |
|||
[Authorize(CmsKitAdminPermissions.Blogs.Create)] |
|||
public Task<BlogDto> CreateAsync(BlogDto input) |
|||
{ |
|||
return BlogAdminAppService.CreateAsync(input); |
|||
} |
|||
|
|||
[HttpDelete] |
|||
[Route("{id}")] |
|||
[Authorize(CmsKitAdminPermissions.Blogs.Delete)] |
|||
public Task DeleteAsync(Guid id) |
|||
{ |
|||
return BlogAdminAppService.DeleteAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{id}")] |
|||
[Authorize(CmsKitAdminPermissions.Blogs.Default)] |
|||
public Task<BlogDto> GetAsync(Guid id) |
|||
{ |
|||
return BlogAdminAppService.GetAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Authorize(CmsKitAdminPermissions.Blogs.Default)] |
|||
public Task<PagedResultDto<BlogDto>> GetListAsync([FromQuery] BlogGetListInput input) |
|||
{ |
|||
return BlogAdminAppService.GetListAsync(input); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("{id}")] |
|||
[Authorize(CmsKitAdminPermissions.Blogs.Update)] |
|||
public Task<BlogDto> UpdateAsync(Guid id, BlogDto input) |
|||
{ |
|||
return BlogAdminAppService.UpdateAsync(id, input); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Http; |
|||
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.Permissions; |
|||
|
|||
namespace Volo.CmsKit.Admin.Blogs |
|||
{ |
|||
[RequiresGlobalFeature(typeof(BlogsFeature))] |
|||
[RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)] |
|||
[Area("cms-kit")] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)] |
|||
[Route("api/cms-kit-admin/blogs/blog-posts")] |
|||
public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppService |
|||
{ |
|||
protected readonly IBlogPostAdminAppService BlogPostAdminAppService; |
|||
|
|||
public BlogPostAdminController(IBlogPostAdminAppService blogPostAdminAppService) |
|||
{ |
|||
BlogPostAdminAppService = blogPostAdminAppService; |
|||
} |
|||
|
|||
[HttpPost] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)] |
|||
public virtual Task<BlogPostDto> CreateAsync(CreateUpdateBlogPostDto input) |
|||
{ |
|||
return BlogPostAdminAppService.CreateAsync(input); |
|||
} |
|||
|
|||
[HttpDelete] |
|||
[Route("{id}")] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Delete)] |
|||
public virtual Task DeleteAsync(Guid id) |
|||
{ |
|||
return BlogPostAdminAppService.DeleteAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{id:Guid}")] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)] |
|||
public virtual Task<BlogPostDto> GetAsync(Guid id) |
|||
{ |
|||
return BlogPostAdminAppService.GetAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{blogSlug}/{blogPostSlug}")] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)] |
|||
public virtual Task<BlogPostDto> GetBySlugAsync(string blogSlug, string blogPostSlug) |
|||
{ |
|||
return BlogPostAdminAppService.GetBySlugAsync(blogSlug, blogPostSlug); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{id}/cover-image")] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)] |
|||
public virtual 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 BlogPostAdminAppService.GetCoverImageAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Default)] |
|||
public virtual Task<PagedResultDto<BlogPostDto>> GetListAsync(PagedAndSortedResultRequestDto input) |
|||
{ |
|||
return BlogPostAdminAppService.GetListAsync(input); |
|||
} |
|||
|
|||
[NonAction] |
|||
public virtual Task SetCoverImageAsync(Guid id, RemoteStreamContent streamContent) |
|||
{ |
|||
return BlogPostAdminAppService.SetCoverImageAsync(id, streamContent); |
|||
} |
|||
|
|||
[HttpPost] |
|||
[Route("{id}/cover-image")] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Update)] |
|||
public virtual async Task<IActionResult> UploadCoverImageAsync(Guid id, IFormFile file) |
|||
{ |
|||
if (file == null) |
|||
{ |
|||
return BadRequest(); |
|||
} |
|||
|
|||
using (var stream = file.OpenReadStream()) |
|||
{ |
|||
await BlogPostAdminAppService.SetCoverImageAsync(id, new RemoteStreamContent(stream)); |
|||
} |
|||
|
|||
return CreatedAtAction(nameof(GetCoverImageAsync), new { id }); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("{id}")] |
|||
[Authorize(CmsKitAdminPermissions.BlogPosts.Update)] |
|||
public virtual Task<BlogPostDto> UpdateAsync(Guid id, CreateUpdateBlogPostDto input) |
|||
{ |
|||
return BlogPostAdminAppService.UpdateAsync(id, input); |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public class BlogConsts |
|||
{ |
|||
public static int MaxNameLength { get; set; } = 64; |
|||
public static int MaxSlugLength { get; set; } = 64; |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public static class BlogPostConsts |
|||
{ |
|||
public static int MaxTitleLength { get; set; } = 64; |
|||
|
|||
public static int MaxSlugLength { get; set; } = 256; |
|||
|
|||
public static int MinSlugLength { get; set; } = 2; |
|||
|
|||
public static int MaxShortDescriptionLength { get; set; } = 256; |
|||
|
|||
public const string EntityType = "BlogPost"; |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.GlobalFeatures; |
|||
|
|||
namespace Volo.CmsKit.GlobalFeatures |
|||
{ |
|||
[GlobalFeatureName(Name)] |
|||
public class BlogsFeature : GlobalFeature |
|||
{ |
|||
public const string Name = "CmsKit.Blogs"; |
|||
|
|||
internal BlogsFeature( |
|||
[NotNull] GlobalCmsKitFeatures cmsKit |
|||
) : base(cmsKit) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain.Entities.Auditing; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.CmsKit.Blogs.Extensions; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public class Blog : FullAuditedAggregateRoot<Guid>, IMultiTenant |
|||
{ |
|||
public Blog( |
|||
Guid id, |
|||
[NotNull] string name, |
|||
[NotNull] string slug, |
|||
[CanBeNull] Guid? tenantId = null) : base(id) |
|||
{ |
|||
SetName(name); |
|||
SetSlug(slug); |
|||
TenantId = tenantId; |
|||
} |
|||
|
|||
public string Name { get; protected set; } |
|||
|
|||
public string Slug { get; protected set; } |
|||
|
|||
public Guid? TenantId { get; protected set; } |
|||
|
|||
public void SetName(string name) |
|||
{ |
|||
Name = Check.NotNullOrWhiteSpace(name, nameof(name), maxLength: BlogConsts.MaxNameLength); |
|||
} |
|||
|
|||
public void SetSlug(string slug) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(slug, nameof(slug), maxLength: BlogConsts.MaxNameLength); |
|||
|
|||
Slug = slug.NormalizeSlug(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using System.Text.RegularExpressions; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain.Entities.Auditing; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.CmsKit.Blogs; |
|||
using Volo.CmsKit.Blogs.Extensions; |
|||
using Volo.CmsKit.Users; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public class BlogPost : FullAuditedAggregateRootWithUser<Guid, CmsUser>, IMultiTenant |
|||
{ |
|||
public Guid BlogId { get; protected set; } |
|||
|
|||
public string Title { get; protected set; } |
|||
|
|||
public string Slug { get; protected set; } |
|||
|
|||
public string ShortDescription { get; protected set; } |
|||
|
|||
public Guid? TenantId { get; protected set; } |
|||
|
|||
protected BlogPost() |
|||
{ |
|||
} |
|||
|
|||
public BlogPost( |
|||
Guid id, |
|||
Guid blogId, |
|||
[NotNull] string title, |
|||
[NotNull] string slug, |
|||
[CanBeNull] string shortDescription = null) : base(id) |
|||
{ |
|||
BlogId = blogId; |
|||
SetTitle(title); |
|||
SetSlug(slug); |
|||
ShortDescription = shortDescription; |
|||
} |
|||
|
|||
public void SetTitle(string title) |
|||
{ |
|||
Title = Check.NotNullOrWhiteSpace(title, nameof(title), BlogPostConsts.MaxTitleLength); |
|||
} |
|||
|
|||
internal void SetSlug(string slug) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(slug, nameof(slug), BlogPostConsts.MaxSlugLength, BlogPostConsts.MinSlugLength); |
|||
|
|||
Slug = slug.NormalizeSlug(); |
|||
} |
|||
|
|||
public void SetShortDescription(string shortDescription) |
|||
{ |
|||
ShortDescription = Check.Length(shortDescription, nameof(shortDescription), BlogPostConsts.MaxShortDescriptionLength); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.BlobStoring; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
[BlobContainerName("blog-post-cover-images")] |
|||
public class BlogPostCoverImageContainer |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.Domain.Services; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public class BlogPostManager : DomainService, IBlogPostManager |
|||
{ |
|||
protected readonly IBlogPostRepository blogPostRepository; |
|||
protected readonly IBlogRepository blogRepository; |
|||
|
|||
public BlogPostManager( |
|||
IBlogPostRepository blogPostRepository, |
|||
IBlogRepository blogRepository) |
|||
{ |
|||
this.blogPostRepository = blogPostRepository; |
|||
this.blogRepository = blogRepository; |
|||
} |
|||
|
|||
public async Task<BlogPost> CreateAsync(BlogPost blogPost) |
|||
{ |
|||
await CheckBlogExistenceAsync(blogPost.BlogId); |
|||
|
|||
await CheckSlugExistenceAsync(blogPost.BlogId, blogPost.Slug); |
|||
|
|||
return await blogPostRepository.InsertAsync(blogPost); |
|||
} |
|||
|
|||
public async Task UpdateAsync(BlogPost blogPost) |
|||
{ |
|||
await CheckBlogExistenceAsync(blogPost.BlogId); |
|||
|
|||
await blogPostRepository.UpdateAsync(blogPost); |
|||
} |
|||
|
|||
public async Task SetSlugUrlAsync(BlogPost blogPost, string newSlug) |
|||
{ |
|||
await CheckSlugExistenceAsync(blogPost.BlogId, newSlug); |
|||
|
|||
blogPost.SetSlug(newSlug); |
|||
} |
|||
|
|||
private async Task CheckSlugExistenceAsync(Guid blogId, string slug) |
|||
{ |
|||
if (await blogPostRepository.SlugExistsAsync(blogId, slug)) |
|||
{ |
|||
throw new BlogPostSlugAlreadyExistException(blogId, slug); |
|||
} |
|||
} |
|||
|
|||
private async Task CheckBlogExistenceAsync(Guid blogId) |
|||
{ |
|||
if (!await blogRepository.ExistsAsync(blogId)) |
|||
throw new EntityNotFoundException(typeof(Blog), blogId); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
using System; |
|||
using Volo.Abp; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public class BlogPostSlugAlreadyExistException : BusinessException |
|||
{ |
|||
internal BlogPostSlugAlreadyExistException(string code = null, string message = null, string details = null, Exception innerException = null, Microsoft.Extensions.Logging.LogLevel logLevel = Microsoft.Extensions.Logging.LogLevel.Warning) : base(code, message, details, innerException, logLevel) |
|||
{ |
|||
} |
|||
|
|||
internal BlogPostSlugAlreadyExistException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext context) : base(serializationInfo, context) |
|||
{ |
|||
} |
|||
|
|||
public BlogPostSlugAlreadyExistException(Guid blogId, string slug) |
|||
{ |
|||
Slug = slug; |
|||
BlogId = blogId; |
|||
|
|||
Code = CmsKitErrorCodes.Blogs.SlugAlreadyExist; |
|||
|
|||
WithData(nameof(Slug), Slug); |
|||
WithData(nameof(BlogId), BlogId); |
|||
} |
|||
|
|||
public string Slug { get; } |
|||
|
|||
public Guid BlogId { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using Slugify; |
|||
using Unidecode.NET; |
|||
|
|||
namespace Volo.CmsKit.Blogs.Extensions |
|||
{ |
|||
public static class SlugExtensions |
|||
{ |
|||
public static string NormalizeSlug(this string value) |
|||
{ |
|||
var slugHelper = new SlugHelper(); |
|||
|
|||
return slugHelper.GenerateSlug(value?.Unidecode()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public interface IBlogPostManager |
|||
{ |
|||
Task<BlogPost> CreateAsync(BlogPost blogPost); |
|||
|
|||
Task UpdateAsync(BlogPost blogPost); |
|||
|
|||
Task SetSlugUrlAsync(BlogPost blogPost, string newSlug); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public interface IBlogPostRepository : IBasicRepository<BlogPost, Guid> |
|||
{ |
|||
Task<bool> SlugExistsAsync(Guid blogId, string slug, CancellationToken cancellationToken = default); |
|||
|
|||
Task<BlogPost> GetBySlugAsync(Guid blogId, string slug, 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); |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public interface IBlogRepository : IBasicRepository<Blog, Guid> |
|||
{ |
|||
public Task<Blog> GetBySlugAsync(string slug); |
|||
Task<bool> ExistsAsync(Guid blogId); |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
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 |
|||
{ |
|||
public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPost, Guid>, IBlogPostRepository |
|||
{ |
|||
public EfCoreBlogPostRepository(IDbContextProvider<CmsKitDbContext> dbContextProvider) : base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public async Task<BlogPost> GetBySlugAsync(Guid blogId, string slug, CancellationToken cancellationToken = default) |
|||
{ |
|||
var dbSet = await GetDbSetAsync(); |
|||
|
|||
return await dbSet |
|||
.Include(i=> i.Creator) |
|||
.Where(x => |
|||
x.BlogId == blogId && x.Slug.ToLower() == slug) |
|||
.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(Guid blogId, string slug, CancellationToken cancellationToken = default) |
|||
{ |
|||
var dbSet = await GetDbSetAsync(); |
|||
|
|||
return await dbSet.AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug, cancellationToken); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using System; |
|||
using System.Security.Cryptography.X509Certificates; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.CmsKit.EntityFrameworkCore; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public class EfCoreBlogRepository : EfCoreRepository<ICmsKitDbContext, Blog, Guid>, IBlogRepository |
|||
{ |
|||
public EfCoreBlogRepository(IDbContextProvider<ICmsKitDbContext> dbContextProvider) : base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public async Task<bool> ExistsAsync(Guid blogId) |
|||
{ |
|||
return await (await GetQueryableAsync()).AnyAsync(x => x.Id == blogId); |
|||
} |
|||
|
|||
public Task<Blog> GetBySlugAsync(string slug) |
|||
{ |
|||
return GetAsync(x => x.Slug == slug); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
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 |
|||
{ |
|||
public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, BlogPost, Guid>, IBlogPostRepository |
|||
{ |
|||
public MongoBlogPostRepository(IMongoDbContextProvider<CmsKitMongoDbContext> dbContextProvider) : base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public Task<BlogPost> GetBySlugAsync(Guid blogId, string slug, CancellationToken cancellationToken = default) |
|||
{ |
|||
return GetAsync(x => |
|||
x.BlogId == blogId && |
|||
x.Slug.ToLower() == slug, |
|||
includeDetails: true, |
|||
cancellationToken: cancellationToken); |
|||
} |
|||
|
|||
public async Task<int> GetCountAsync(Guid blogId, CancellationToken cancellationToken = default) |
|||
{ |
|||
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 queryable.AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug, cancellationToken); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
using MongoDB.Driver.Core.Operations; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories.MongoDB; |
|||
using Volo.Abp.MongoDB; |
|||
using Volo.CmsKit.Blogs; |
|||
|
|||
namespace Volo.CmsKit.MongoDB.Blogs |
|||
{ |
|||
public class MongoBlogRepository : MongoDbRepository<ICmsKitMongoDbContext, Blog, Guid>, IBlogRepository |
|||
{ |
|||
public MongoBlogRepository(IMongoDbContextProvider<ICmsKitMongoDbContext> dbContextProvider) : base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public async Task<bool> ExistsAsync(Guid blogId) |
|||
{ |
|||
return await AsyncExecuter.AnyAsync( |
|||
await GetQueryableAsync(), |
|||
x => x.Id == blogId); |
|||
} |
|||
|
|||
public Task<Blog> GetBySlugAsync(string slug) |
|||
{ |
|||
return GetAsync(x => x.Slug == slug); |
|||
} |
|||
} |
|||
} |
|||
@ -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 Slug { get; set; } |
|||
|
|||
public string ShortDescription { get; set; } |
|||
} |
|||
} |
|||
@ -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 blogSlug, PagedAndSortedResultRequestDto input); |
|||
|
|||
Task<BlogPostPublicDto> GetAsync(string blogSlug, string blogPostSlug); |
|||
|
|||
Task<RemoteStreamContent> GetCoverImageAsync(Guid id); |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
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 IBlogPostRepository BlogPostRepository { get; } |
|||
|
|||
protected IBlobContainer<BlogPostCoverImageContainer> BlobContainer { get; } |
|||
|
|||
public BlogPostPublicAppService( |
|||
IBlogRepository blogRepository, |
|||
IBlogPostRepository blogPostRepository, |
|||
IBlobContainer<BlogPostCoverImageContainer> blobContainer) |
|||
{ |
|||
BlogRepository = blogRepository; |
|||
BlogPostRepository = blogPostRepository; |
|||
BlobContainer = blobContainer; |
|||
} |
|||
|
|||
public async Task<BlogPostPublicDto> GetAsync(string blogSlug, string blogPostSlug) |
|||
{ |
|||
var blog = await BlogRepository.GetBySlugAsync(blogSlug); |
|||
|
|||
var blogPost = await BlogPostRepository.GetBySlugAsync(blog.Id, blogPostSlug); |
|||
|
|||
return ObjectMapper.Map<BlogPost, BlogPostPublicDto>(blogPost); |
|||
} |
|||
|
|||
public async Task<PagedResultDto<BlogPostPublicDto>> GetListAsync(string blogSlug, PagedAndSortedResultRequestDto input) |
|||
{ |
|||
var blog = await BlogRepository.GetBySlugAsync(blogSlug); |
|||
|
|||
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); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
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] |
|||
[Route("{blogSlug}/{blogPostSlug}")] |
|||
public Task<BlogPostPublicDto> GetAsync(string blogSlug, string blogPostSlug) |
|||
{ |
|||
return BlogPostPublicAppService.GetAsync(blogSlug, blogPostSlug); |
|||
} |
|||
|
|||
[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] |
|||
[Route("{blogSlug}")] |
|||
public Task<PagedResultDto<BlogPostPublicDto>> GetListAsync(string blogSlug, PagedAndSortedResultRequestDto input) |
|||
{ |
|||
return BlogPostPublicAppService.GetListAsync(blogSlug, input); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.ActionConstraints; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.GlobalFeatures; |
|||
using Volo.CmsKit.GlobalFeatures; |
|||
using Volo.CmsKit.Public.Pages; |
|||
|
|||
namespace Volo.CmsKit.Public.Web.Controllers |
|||
{ |
|||
[RequiresGlobalFeature(typeof(PagesFeature))] |
|||
public class PageController : CmsKitPublicControllerBase |
|||
{ |
|||
protected IPageAppService PageAppService { get; } |
|||
|
|||
public PageController(IPageAppService pageAppService) |
|||
{ |
|||
PageAppService = pageAppService; |
|||
} |
|||
|
|||
//[HttpGet("/{*url}", Order = int.MaxValue)]
|
|||
public async Task<IActionResult> IndexAsync(string url) |
|||
{ |
|||
var page = await PageAppService.FindByUrlAsync(url); |
|||
|
|||
if (page == null) |
|||
{ |
|||
return NotFound(); |
|||
} |
|||
|
|||
return View("~/Views/Page/Index.cshtml", page); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
@page "/blogs/{blogSlug}/{blogPostSlug}" |
|||
|
|||
@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.BlogSlug, |
|||
Model.BlogPostSlug |
|||
}) |
|||
|
|||
@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() |
|||
}) |
|||
} |
|||
@ -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 BlogSlug { get; set; } |
|||
|
|||
[BindProperty(SupportsGet = true)] |
|||
public string BlogPostSlug { 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(BlogSlug, BlogPostSlug); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
@page "/blogs/{blogSlug}" |
|||
|
|||
@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" style="max-width:200px;max-height:200px;" 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.BlogSlug/@blog.Slug"> |
|||
<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> |
|||
|
|||
@ -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 BlogSlug { 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( |
|||
BlogSlug, |
|||
new PagedAndSortedResultRequestDto |
|||
{ |
|||
SkipCount = PageSize * (CurrentPage - 1), |
|||
MaxResultCount = PageSize |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -1,13 +0,0 @@ |
|||
@page "{*pageUrl}" |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.CmsKit.Localization |
|||
@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages |
|||
@model Volo.CmsKit.Public.Web.Pages.CmsKit.Pages.IndexModel |
|||
@inject IHtmlLocalizer<CmsKitResource> L |
|||
|
|||
@await Component.InvokeAsync(typeof(DefaultPageViewComponent), |
|||
new |
|||
{ |
|||
pageId = Model.Page.Id, |
|||
title = Model.Page.Title |
|||
}) |
|||
@ -1,34 +0,0 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.CmsKit.Public.Pages; |
|||
using Volo.CmsKit.Web.Pages; |
|||
|
|||
namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Pages |
|||
{ |
|||
public class IndexModel : CommonPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
public string PageUrl { get; set; } |
|||
|
|||
protected readonly IPageAppService PageAppService; |
|||
|
|||
public PageDto Page; |
|||
|
|||
public IndexModel(IPageAppService pageAppService) |
|||
{ |
|||
PageAppService = pageAppService; |
|||
} |
|||
|
|||
public async Task<IActionResult> OnGetAsync() |
|||
{ |
|||
Page = await PageAppService.FindByUrlAsync(PageUrl); |
|||
|
|||
if (Page == null) |
|||
{ |
|||
return NotFound(); |
|||
} |
|||
|
|||
return Page(); |
|||
} |
|||
} |
|||
} |
|||
@ -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" style="max-width:200px;max-height:200px;" onerror="this.src='https://dummyimage.com/300x200/a3a3a3/fff.png'" />*@ |
|||
@await Component.InvokeAsync(typeof(ContentViewComponent), new |
|||
{ |
|||
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, |
|||
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> |
|||
|
|||
|
|||
@ -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 blogSlug, string blogPostSlug) |
|||
{ |
|||
var blogPost = await BlogPostPublicAppService.GetAsync(blogSlug, blogPostSlug); |
|||
|
|||
return View("~/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml", blogPost); |
|||
} |
|||
} |
|||
} |
|||
@ -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> |
|||
@ -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; } |
|||
} |
|||
} |
|||
} |
|||
@ -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)
|
|||
} |
|||
} |
|||
} |
|||
@ -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" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
@model Volo.CmsKit.Public.Pages.PageDto |
|||
|
|||
@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages |
|||
|
|||
@await Component.InvokeAsync(typeof(DefaultPageViewComponent), new |
|||
{ |
|||
pageId = Model.Id, |
|||
title = Model.Title |
|||
}) |
|||
@ -0,0 +1,225 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Castle.DynamicProxy.Generators; |
|||
using Shouldly; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Content; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.CmsKit.Admin.Blogs; |
|||
using Xunit; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public class BlogPostAdminAppService_Tests : CmsKitApplicationTestBase |
|||
{ |
|||
private readonly IBlogPostAdminAppService blogPostAdminAppService; |
|||
private readonly CmsKitTestData cmsKitTestData; |
|||
private readonly IBlogPostRepository blogPostRepository; |
|||
|
|||
public BlogPostAdminAppService_Tests() |
|||
{ |
|||
blogPostAdminAppService = GetRequiredService<IBlogPostAdminAppService>(); |
|||
cmsKitTestData = GetRequiredService<CmsKitTestData>(); |
|||
blogPostRepository = GetRequiredService<IBlogPostRepository>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task CreateAsync_ShouldWorkProperly_WithCorrectData() |
|||
{ |
|||
var title = "My awesome new Post"; |
|||
var slug = "my-awesome-new-post"; |
|||
var shortDescription = "This blog is all about awesomeness 🤗!"; |
|||
|
|||
var created = await blogPostAdminAppService.CreateAsync(new CreateUpdateBlogPostDto |
|||
{ |
|||
BlogId = cmsKitTestData.Blog_Id, |
|||
Title = title, |
|||
Slug = slug, |
|||
ShortDescription = shortDescription |
|||
}); |
|||
|
|||
created.Id.ShouldNotBe(Guid.Empty); |
|||
|
|||
var blogPost = await blogPostRepository.GetAsync(created.Id); |
|||
|
|||
blogPost.Title.ShouldBe(title); |
|||
blogPost.Slug.ShouldBe(slug); |
|||
blogPost.ShortDescription.ShouldBe(shortDescription); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task CreateAsync_ShouldThrowException_WithNonExistingBlogId() |
|||
{ |
|||
var title = "Another My Awesome New Post"; |
|||
var slug = "another-my-awesome-new-post"; |
|||
var shortDescription = "This blog is all about awesomeness 🤗!"; |
|||
|
|||
var dto = new CreateUpdateBlogPostDto |
|||
{ |
|||
// Non-existing Id
|
|||
BlogId = Guid.NewGuid(), |
|||
Title = title, |
|||
Slug = slug, |
|||
ShortDescription = shortDescription |
|||
}; |
|||
|
|||
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () => |
|||
await blogPostAdminAppService.CreateAsync(dto)); |
|||
|
|||
exception.EntityType.ShouldBe(typeof(Blog)); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetAsync_ShouldWorkProperly_WithExistingId() |
|||
{ |
|||
var blogPost = await blogPostAdminAppService.GetAsync(cmsKitTestData.BlogPost_1_Id); |
|||
|
|||
blogPost.Title.ShouldBe(cmsKitTestData.BlogPost_1_Title); |
|||
blogPost.Slug.ShouldBe(cmsKitTestData.BlogPost_1_Slug); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetAsync_ShouldThrowException_WithNonExistingId() |
|||
{ |
|||
var nonExistingId = Guid.NewGuid(); |
|||
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () => |
|||
await blogPostAdminAppService.GetAsync(nonExistingId)); |
|||
|
|||
exception.EntityType.ShouldBe(typeof(BlogPost)); |
|||
exception.Id.ShouldBe(nonExistingId); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetBySlugAsync_ShouldWorkProperly_WithExistingSlug() |
|||
{ |
|||
var blogPost = await blogPostAdminAppService.GetBySlugAsync(cmsKitTestData.BlogSlug, cmsKitTestData.BlogPost_1_Slug); |
|||
|
|||
blogPost.Id.ShouldBe(cmsKitTestData.BlogPost_1_Id); |
|||
blogPost.Title.ShouldBe(cmsKitTestData.BlogPost_1_Title); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetBySlugAsync_ShouldThrowException_WithNonExistingBlogPostSlug() |
|||
{ |
|||
var nonExistingSlug = "any-other-url"; |
|||
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () => |
|||
await blogPostAdminAppService.GetBySlugAsync(cmsKitTestData.BlogSlug, nonExistingSlug)); |
|||
|
|||
exception.EntityType.ShouldBe(typeof(BlogPost)); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetBySlugAsync_ShouldThrowException_WithNonExistingBlogSlug() |
|||
{ |
|||
var nonExistingSlug = "any-other-url"; |
|||
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () => |
|||
await blogPostAdminAppService.GetBySlugAsync(nonExistingSlug, cmsKitTestData.Page_1_Url)); |
|||
|
|||
exception.EntityType.ShouldBe(typeof(Blog)); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetListAsync_ShouldWorkProperly_WithDefaultParameters() |
|||
{ |
|||
var list = await blogPostAdminAppService.GetListAsync(new PagedAndSortedResultRequestDto()); |
|||
|
|||
list.ShouldNotBeNull(); |
|||
list.TotalCount.ShouldBe(2); |
|||
list.Items.ShouldNotBeEmpty(); |
|||
list.Items.Count.ShouldBe(2); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task UpdateAsync_ShouldWorkProperly_WithRegularDatas() |
|||
{ |
|||
var shortDescription = "Another short description"; |
|||
var title = "[Solved] Another Blog Post"; |
|||
var slug = "another-short-blog-post"; |
|||
|
|||
await blogPostAdminAppService.UpdateAsync(cmsKitTestData.BlogPost_2_Id, new CreateUpdateBlogPostDto |
|||
{ |
|||
BlogId = cmsKitTestData.Blog_Id, |
|||
ShortDescription = shortDescription, |
|||
Title = title, |
|||
Slug = slug, |
|||
}); |
|||
|
|||
var blogPost = await blogPostRepository.GetAsync(cmsKitTestData.BlogPost_2_Id); |
|||
|
|||
blogPost.Title.ShouldBe(title); |
|||
blogPost.ShortDescription.ShouldBe(shortDescription); |
|||
blogPost.Slug.ShouldBe(slug); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task UpdateAsync_ShouldThrowException_WhileChangingWithNonExistingBlogId() |
|||
{ |
|||
var nonExistingId = Guid.NewGuid(); |
|||
|
|||
var dto = new CreateUpdateBlogPostDto |
|||
{ |
|||
BlogId = nonExistingId, |
|||
Title = cmsKitTestData.Page_2_Title, |
|||
Slug = cmsKitTestData.BlogPost_2_Slug |
|||
}; |
|||
|
|||
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () => |
|||
await blogPostAdminAppService.UpdateAsync(cmsKitTestData.BlogPost_2_Id, dto)); |
|||
|
|||
exception.EntityType.ShouldBe(typeof(Blog)); |
|||
exception.Id.ShouldBe(nonExistingId); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task UpdateAsync_ShouldThrowException_WhileUpdatingWithAlreadyExistingSlug() |
|||
{ |
|||
var dto = new CreateUpdateBlogPostDto |
|||
{ |
|||
BlogId = cmsKitTestData.Blog_Id, |
|||
Title = "Some new title", |
|||
Slug = cmsKitTestData.BlogPost_1_Slug |
|||
}; |
|||
|
|||
var exception = await Should.ThrowAsync<BlogPostSlugAlreadyExistException>(async () => |
|||
await blogPostAdminAppService.UpdateAsync(cmsKitTestData.BlogPost_2_Id, dto)); |
|||
|
|||
exception.Slug.ShouldBe(cmsKitTestData.BlogPost_1_Slug); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task DeleteAsync_ShouldWorkProperly_WithExistingId() |
|||
{ |
|||
await blogPostAdminAppService.DeleteAsync(cmsKitTestData.Page_2_Id); |
|||
|
|||
var exception = await Should.ThrowAsync<EntityNotFoundException>(async () => |
|||
await blogPostRepository.GetAsync(cmsKitTestData.Page_2_Id)); |
|||
|
|||
exception.EntityType.ShouldBe(typeof(BlogPost)); |
|||
exception.Id.ShouldBe(cmsKitTestData.Page_2_Id); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task SetCoverImage_ShouldNotThrowException_WithCorrectData() |
|||
{ |
|||
using (var imageStream = GetSampleImageStream()) |
|||
{ |
|||
await WithUnitOfWorkAsync(async () => |
|||
{ |
|||
await blogPostAdminAppService.SetCoverImageAsync( |
|||
cmsKitTestData.BlogPost_2_Id, |
|||
new RemoteStreamContent(imageStream)); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
private Stream GetSampleImageStream() |
|||
{ |
|||
var assembly = GetType().Assembly; |
|||
var resourceName = "Volo.CmsKit.Data.BlogPostSample.png"; |
|||
|
|||
return assembly.GetManifestResourceStream(resourceName); |
|||
} |
|||
// SetCoverImage
|
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 6.8 KiB |
@ -0,0 +1,92 @@ |
|||
using Shouldly; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Guids; |
|||
using Volo.CmsKit.Tags; |
|||
using Xunit; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public class BlogPostManager_Tests : CmsKitDomainTestBase |
|||
{ |
|||
private readonly IBlogPostManager blogPostManager; |
|||
private readonly IGuidGenerator guidGenerator; |
|||
private readonly IBlogPostRepository blogPostRepository; |
|||
private readonly CmsKitTestData cmsKitTestData; |
|||
|
|||
public BlogPostManager_Tests() |
|||
{ |
|||
this.blogPostManager = GetRequiredService<IBlogPostManager>(); |
|||
this.guidGenerator = GetRequiredService<IGuidGenerator>(); |
|||
this.blogPostRepository = GetRequiredService<IBlogPostRepository>(); |
|||
this.cmsKitTestData = GetRequiredService<CmsKitTestData>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task CreateAsync_ShouldWorkProperly_WithCorrectData() |
|||
{ |
|||
var title = "New blog post"; |
|||
var slug = "new-blog-post"; |
|||
|
|||
var created = await blogPostManager.CreateAsync( |
|||
new BlogPost(guidGenerator.Create(), cmsKitTestData.Blog_Id, title, slug)); |
|||
|
|||
created.Id.ShouldNotBe(Guid.Empty); |
|||
|
|||
var blogPost = await blogPostRepository.GetAsync(created.Id); |
|||
blogPost.Title.ShouldBe(title); |
|||
blogPost.Slug.ShouldBe(slug); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task CreateAsync_ShouldThrowException_WhenSlugAlreadyExists() |
|||
{ |
|||
var blogPost = new BlogPost(guidGenerator.Create(), cmsKitTestData.Blog_Id, "Any New Title", cmsKitTestData.BlogPost_1_Slug); |
|||
|
|||
await Should.ThrowAsync<BlogPostSlugAlreadyExistException>(async () => |
|||
await blogPostManager.CreateAsync(blogPost)); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task UpdateAsync_ShoudlWorkProperly_WithCorrectData() |
|||
{ |
|||
var newTitle = "Yet Another Post"; |
|||
|
|||
var blogPost = await blogPostRepository.GetAsync(cmsKitTestData.BlogPost_1_Id); |
|||
|
|||
blogPost.SetTitle(newTitle); |
|||
|
|||
await blogPostManager.UpdateAsync(blogPost); |
|||
|
|||
var updated = await blogPostRepository.GetAsync(cmsKitTestData.BlogPost_1_Id); |
|||
updated.Title.ShouldBe(newTitle); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task SetSlugAsync_ShouldWorkProperly_WithNonExistingSlug() |
|||
{ |
|||
var newSlug = "yet-another-post"; |
|||
|
|||
var blogPost = await blogPostRepository.GetAsync(cmsKitTestData.BlogPost_1_Id); |
|||
|
|||
await blogPostManager.SetSlugUrlAsync(blogPost, newSlug); |
|||
|
|||
blogPost.Slug.ShouldBe(newSlug); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task SetSlugAsync_ShouldThrowException_WithExistingSlug() |
|||
{ |
|||
var blogPost = await blogPostRepository.GetAsync(cmsKitTestData.BlogPost_1_Id); |
|||
|
|||
var exception = await Should.ThrowAsync<BlogPostSlugAlreadyExistException>(async () => |
|||
await blogPostManager.SetSlugUrlAsync(blogPost, cmsKitTestData.BlogPost_2_Slug)); |
|||
|
|||
exception.BlogId.ShouldBe(blogPost.BlogId); |
|||
exception.Slug.ShouldBe(cmsKitTestData.BlogPost_2_Slug); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,140 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Xunit; |
|||
using Volo.CmsKit.Blogs.Extensions; |
|||
using Shouldly; |
|||
using Unidecode.NET; |
|||
|
|||
namespace Volo.CmsKit.Blogs |
|||
{ |
|||
public class SlugExtensions_Tests |
|||
{ |
|||
[Fact] |
|||
public void NormalizeSlug_ShouldWorkProperly() |
|||
{ |
|||
// Arrange
|
|||
var name = "My awesome name"; |
|||
var expected = "my-awesome-name"; |
|||
|
|||
// Act
|
|||
var actual = name.NormalizeSlug(); |
|||
|
|||
// Assert
|
|||
actual.ShouldBe(expected); |
|||
} |
|||
[Fact] |
|||
public void NormalizeSlug_ShouldWorkProperly_WithDot() |
|||
{ |
|||
// Arrange
|
|||
var name = "My Perfect Title v.2"; |
|||
var expected = "my-perfect-title-v.2"; |
|||
|
|||
// Act
|
|||
var actual = name.NormalizeSlug(); |
|||
|
|||
// Assert
|
|||
actual.ShouldBe(expected); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeSlug_ShouldWorkProperly_WithQuestionMark() |
|||
{ |
|||
// Arrange
|
|||
var name = "Are you gonna die?"; |
|||
var expected = "are-you-gonna-die"; |
|||
|
|||
// Act
|
|||
var actual = name.NormalizeSlug(); |
|||
|
|||
// Assert
|
|||
actual.ShouldBe(expected); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeSlug_ShouldWorkProperly_WithAmpersand() |
|||
{ |
|||
// Arrange
|
|||
var name = "We & Machines Challenge"; |
|||
var expected = "we-machines-challenge"; |
|||
|
|||
// Act
|
|||
var actual = name.NormalizeSlug(); |
|||
|
|||
// Assert
|
|||
actual.ShouldBe(expected); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeSlug_ShouldWorkProperly_WithDoubleDash() |
|||
{ |
|||
// Arrange
|
|||
var name = "Go and Code --part 2"; |
|||
var expected = "go-and-code-part-2"; |
|||
|
|||
// Act
|
|||
var actual = name.NormalizeSlug(); |
|||
|
|||
// Assert
|
|||
actual.ShouldBe(expected); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeSlug_ShouldWorkProperly_WithCyrillicChars() |
|||
{ |
|||
// Arrange
|
|||
var name = "Мое классное название"; |
|||
var expected = "moe-klassnoe-nazvanie"; |
|||
|
|||
// Act
|
|||
var actual = name.NormalizeSlug(); |
|||
|
|||
// Assert
|
|||
actual.ShouldBe(expected); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeSlug_ShouldWorkProperly_WithTurkishChars() |
|||
{ |
|||
// Arrange
|
|||
var name = "Özel Türkçe karakterler: ğüşiöç"; |
|||
var expected = "ozel-turkce-karakterler-gusioc"; |
|||
|
|||
// Act
|
|||
var actual = name.NormalizeSlug(); |
|||
|
|||
// Assert
|
|||
actual.ShouldBe(expected); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeSlug_ShouldWorkProperly_WithChineseChars() |
|||
{ |
|||
// Arrange
|
|||
var name = "我的真棒头衔"; |
|||
var expected = "wo-de-zhen-bang-tou-xian"; |
|||
|
|||
// Act
|
|||
var actual = name.NormalizeSlug(); |
|||
|
|||
// Assert
|
|||
actual.ShouldBe(expected); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeSlug_ShouldWorkProperly_WithEmoji() |
|||
{ |
|||
// Arrange
|
|||
var name = "Let's Rock 👊"; |
|||
var expected = "lets-rock"; |
|||
|
|||
// Act
|
|||
var actual = name.NormalizeSlug(); |
|||
|
|||
// Assert
|
|||
actual.ShouldBe(expected); |
|||
} |
|||
} |
|||
} |
|||
@ -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> |
|||
{ |
|||
} |
|||
} |
|||
@ -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> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -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> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -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> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -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> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -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> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -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_WithExistingSlug() |
|||
{ |
|||
var result = await blogPostRepository.SlugExistsAsync(testData.Blog_Id, testData.BlogPost_1_Slug); |
|||
|
|||
result.ShouldBeTrue(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task SlugExistsAsync_ShouldReturnFalse_WithNonExistingSlug() |
|||
{ |
|||
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_Slug); |
|||
|
|||
result.ShouldBeFalse(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetBySlugAsync_ShouldWorkProperly_WithCorrectParameters() |
|||
{ |
|||
var blogPost = await blogPostRepository.GetBySlugAsync(testData.Blog_Id, testData.BlogPost_1_Slug); |
|||
|
|||
blogPost.ShouldNotBeNull(); |
|||
blogPost.Id.ShouldBe(testData.BlogPost_1_Id); |
|||
blogPost.Slug.ShouldBe(testData.BlogPost_1_Slug); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetBySlugAsync_ShouldThrowException_WithNonExistingBlogPostSlug() |
|||
{ |
|||
var nonExistingSlugUrl = "absolutely-non-existing-url"; |
|||
var exception = await Should.ThrowAsync<EntityNotFoundException>( |
|||
async () => await blogPostRepository.GetBySlugAsync(testData.Blog_Id, nonExistingSlugUrl)); |
|||
|
|||
exception.ShouldNotBeNull(); |
|||
exception.EntityType.ShouldBe(typeof(BlogPost)); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetBySlugAsync_ShouldThrowException_WithNonExistingBlogId() |
|||
{ |
|||
var nonExistingBlogId = Guid.NewGuid(); |
|||
var exception = await Should.ThrowAsync<EntityNotFoundException>( |
|||
async () => await blogPostRepository.GetBySlugAsync(nonExistingBlogId, testData.BlogPost_1_Slug)); |
|||
|
|||
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); |
|||
} |
|||
} |
|||
} |
|||
@ -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 GetBySlugAsync_ShouldWorkProperly_WithExistingSlug() |
|||
{ |
|||
var blog = await blogRepository.GetBySlugAsync(testData.BlogSlug); |
|||
|
|||
blog.ShouldNotBeNull(); |
|||
blog.Slug.ShouldBe(testData.BlogSlug); |
|||
blog.Id.ShouldBe(testData.Blog_Id); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetBySlugAsync_ShouldThrowException_WithNonExistingSlug() |
|||
{ |
|||
var nonExistingSlug = "some-blog-slug-that-doesnt-exist"; |
|||
|
|||
var exception = await Should.ThrowAsync<EntityNotFoundException>( |
|||
async () => await blogRepository.GetBySlugAsync(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(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Security.Claims; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Users; |
|||
|
|||
namespace Volo.CmsKit |
|||
{ |
|||
public class CmsKitFakeCurrentUser : ITransientDependency, ICurrentUser |
|||
{ |
|||
private readonly CmsKitTestData cmsKitTestData; |
|||
|
|||
public CmsKitFakeCurrentUser(CmsKitTestData cmsKitTestData) |
|||
{ |
|||
this.cmsKitTestData = cmsKitTestData; |
|||
} |
|||
|
|||
public bool IsAuthenticated { get; } |
|||
public Guid? Id => cmsKitTestData.User1Id; |
|||
public string UserName => cmsKitTestData.User1UserName; |
|||
public string Name { get; } |
|||
public string SurName { get; } |
|||
public string PhoneNumber { get; } |
|||
public bool PhoneNumberVerified { get; } |
|||
public string Email { get; } |
|||
public bool EmailVerified { get; } |
|||
public Guid? TenantId { get; } |
|||
public string[] Roles { get; } |
|||
|
|||
public Claim FindClaim(string claimType) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public Claim[] FindClaims(string claimType) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public Claim[] GetAllClaims() |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public bool IsInRole(string roleName) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue