Browse Source

Merge pull request #7226 from abpframework/cms-kit/blog-initial

CmsKit - Blog Initial Design
pull/7697/head
Ahmet Çotur 6 years ago
committed by GitHub
parent
commit
1ccf95f161
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      modules/cms-kit/host/Volo.CmsKit.Host.Shared/FeatureConfigurer.cs
  2. 1891
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210209082122_UrlSlugToSlug.Designer.cs
  3. 106
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210209082122_UrlSlugToSlug.cs
  4. 168
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs
  5. 19
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogDto.cs
  6. 9
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogGetListInput.cs
  7. 10
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogLookupDto.cs
  8. 15
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs
  9. 27
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateUpdateBlogPostDto.cs
  10. 11
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogAdminAppService.cs
  11. 22
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs
  12. 15
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagSetDto.cs
  13. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/IEntityTagAdminAppService.cs
  14. 17
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs
  15. 16
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs
  16. 37
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs
  17. 118
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs
  18. 10
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs
  19. 30
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs
  20. 1
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs
  21. 39
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs
  22. 68
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs
  23. 115
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs
  24. 42
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs
  25. 2
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Tags/ITagAppService.cs
  26. 20
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Users/CmsUserDto.cs
  27. 3
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationAutoMapperProfile.cs
  28. 2
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs
  29. 8
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogConsts.cs
  30. 15
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs
  31. 5
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs
  32. 17
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/BlogsFeature.cs
  33. 1
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs
  34. 16
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json
  35. 8
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json
  36. 8
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo.CmsKit.Domain.csproj
  37. 41
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs
  38. 59
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs
  39. 9
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostCoverImageContainer.cs
  40. 61
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs
  41. 31
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostSlugAlreadyExistException.cs
  42. 15
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Extensions/SlugExtensions.cs
  43. 14
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostManager.cs
  44. 21
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs
  45. 12
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs
  46. 6
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs
  47. 2
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentManager.cs
  48. 2
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentManager.cs
  49. 2
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs
  50. 66
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs
  51. 27
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs
  52. 3
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs
  53. 45
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs
  54. 3
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitEntityFrameworkCoreModule.cs
  55. 3
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs
  56. 10
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs
  57. 67
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs
  58. 28
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs
  59. 5
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContext.cs
  60. 11
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContextExtensions.cs
  61. 4
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbModule.cs
  62. 15
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/ICmsKitMongoDbContext.cs
  63. 9
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs
  64. 17
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs
  65. 17
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs
  66. 56
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs
  67. 6
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs
  68. 55
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs
  69. 4
      modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs
  70. 37
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/PageController.cs
  71. 63
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml
  72. 33
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs
  73. 47
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml
  74. 45
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml.cs
  75. 13
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml
  76. 34
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml.cs
  77. 33
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml
  78. 29
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/DefaultBlogPostViewComponent.cs
  79. 22
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml
  80. 39
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/DefaultBlogPostCommentViewComponent.cs
  81. 26
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPublicPageBase.cs
  82. 27
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Properties/launchSettings.json
  83. 9
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Views/Page/Index.cshtml
  84. 225
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs
  85. BIN
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Data/BlogPostSample.png
  86. 2
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagPublicAppService_Tests.cs
  87. 4
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Volo.CmsKit.Application.Tests.csproj
  88. 92
      modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Blogs/BlogPostManager_Tests.cs
  89. 140
      modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Blogs/SlugExtensions_Tests.cs
  90. 14
      modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogPostRepository_Test.cs
  91. 14
      modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Blogs/BlogRepository_Test.cs
  92. 14
      modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Tags/EntityTagRepository_Test.cs
  93. 16
      modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogPostRepository_Test.cs
  94. 16
      modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Blogs/BlogRepository_Test.cs
  95. 16
      modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Tags/EntityTagRepository_Test.cs
  96. 125
      modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs
  97. 65
      modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs
  98. 24
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs
  99. 53
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitFakeCurrentUser.cs
  100. 1
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestBase.cs

2
modules/cms-kit/host/Volo.CmsKit.Host.Shared/FeatureConfigurer.cs

@ -1,5 +1,6 @@
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Threading;
using Volo.CmsKit.GlobalFeatures;
namespace Volo.CmsKit
{
@ -12,6 +13,7 @@ namespace Volo.CmsKit
OneTimeRunner.Run(() =>
{
GlobalFeatureManager.Instance.Modules.CmsKit().EnableAll();
GlobalFeatureManager.Instance.Modules.CmsKit().Disable<PagesFeature>();
});
}
}

1891
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210209082122_UrlSlugToSlug.Designer.cs

File diff suppressed because it is too large

106
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210209082122_UrlSlugToSlug.cs

@ -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");
}
}
}

168
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs

@ -19,7 +19,7 @@ namespace Volo.CmsKit.Migrations
.UseIdentityColumns()
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer)
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.1");
.HasAnnotation("ProductVersion", "5.0.2");
modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b =>
{
@ -1124,6 +1124,151 @@ namespace Volo.CmsKit.Migrations
b.ToTable("AbpTenantConnectionStrings");
});
modelBuilder.Entity("Volo.CmsKit.Blogs.Blog", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("Slug")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.ToTable("CmsBlogs");
});
modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("BlogId")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("ShortDescription")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("Slug")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.HasKey("Id");
b.HasIndex("CreatorId");
b.HasIndex("DeleterId");
b.HasIndex("LastModifierId");
b.HasIndex("Slug", "BlogId");
b.ToTable("CmsBlogPosts");
});
modelBuilder.Entity("Volo.CmsKit.Comments.Comment", b =>
{
b.Property<Guid>("Id")
@ -1678,6 +1823,27 @@ namespace Volo.CmsKit.Migrations
.IsRequired();
});
modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b =>
{
b.HasOne("Volo.CmsKit.Users.CmsUser", "Creator")
.WithMany()
.HasForeignKey("CreatorId");
b.HasOne("Volo.CmsKit.Users.CmsUser", "Deleter")
.WithMany()
.HasForeignKey("DeleterId");
b.HasOne("Volo.CmsKit.Users.CmsUser", "LastModifier")
.WithMany()
.HasForeignKey("LastModifierId");
b.Navigation("Creator");
b.Navigation("Deleter");
b.Navigation("LastModifier");
});
modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b =>
{
b.Navigation("Actions");

19
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogDto.cs

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

9
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogGetListInput.cs

@ -0,0 +1,9 @@
using Volo.Abp.Application.Dtos;
namespace Volo.CmsKit.Admin.Blogs
{
public class BlogGetListInput : PagedAndSortedResultRequestDto
{
public string Filter { get; set; }
}
}

10
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogLookupDto.cs

@ -0,0 +1,10 @@
using System;
namespace Volo.CmsKit.Admin.Blogs
{
public class BlogLookupDto
{
public Guid Id { get; set; }
public string Name { get; set; }
}
}

15
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs

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

27
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateUpdateBlogPostDto.cs

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

11
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogAdminAppService.cs

@ -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>
{
}
}

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

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

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

17
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs

@ -1,4 +1,5 @@
using Volo.Abp.Authorization.Permissions;

using Volo.Abp.Authorization.Permissions;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Localization;
using Volo.CmsKit.GlobalFeatures;
@ -12,7 +13,6 @@ namespace Volo.CmsKit.Permissions
{
var cmsGroup = context.GetGroupOrNull(CmsKitAdminPermissions.GroupName) ?? context.AddGroup(CmsKitAdminPermissions.GroupName, L("Permission:CmsKit"));
if (GlobalFeatureManager.Instance.IsEnabled<ContentsFeature>())
{
var contentGroup = cmsGroup.AddPermission(CmsKitAdminPermissions.Contents.Default, L("Permission:Contents"));
@ -35,6 +35,19 @@ namespace Volo.CmsKit.Permissions
pageManagement.AddChild(CmsKitAdminPermissions.Pages.Update, L("Permission:PageManagement:Update"));
pageManagement.AddChild(CmsKitAdminPermissions.Pages.Delete, L("Permission:PageManagement:Delete"));
}
if (GlobalFeatureManager.Instance.IsEnabled<BlogsFeature>())
{
var blogManagement = cmsGroup.AddPermission(CmsKitAdminPermissions.Blogs.Default, L("Permission:BlogManagement"));
blogManagement.AddChild(CmsKitAdminPermissions.Blogs.Create, L("Permission:BlogManagement.Create"));
blogManagement.AddChild(CmsKitAdminPermissions.Blogs.Update, L("Permission:BlogManagement.Update"));
blogManagement.AddChild(CmsKitAdminPermissions.Blogs.Delete, L("Permission:BlogManagement.Delete"));
var blogPostManagement = cmsGroup.AddPermission(CmsKitAdminPermissions.BlogPosts.Default, L("Permission:BlogPostManagement"));
blogManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Create, L("Permission:BlogPostManagement.Create"));
blogManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Update, L("Permission:BlogPostManagement.Update"));
blogManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Delete, L("Permission:BlogPostManagement.Delete"));
}
}
private static LocalizableString L(string name)

16
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs

@ -29,5 +29,21 @@ namespace Volo.CmsKit.Permissions
public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete";
}
public static class Blogs
{
public const string Default = GroupName + ".Blogs";
public const string Create = Default + ".Create";
public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete";
}
public static class BlogPosts
{
public const string Default = GroupName + ".BlogPosts";
public const string Create = Default + ".Create";
public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete";
}
}
}

37
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs

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

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

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

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

@ -1,6 +1,8 @@
using AutoMapper;
using Volo.CmsKit.Admin.Blogs;
using Volo.CmsKit.Admin.Contents;
using Volo.CmsKit.Admin.Pages;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Admin.Tags;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Pages;
@ -19,6 +21,14 @@ namespace Volo.CmsKit.Admin
CreateMap<ContentCreateDto, Content>(MemberList.Source);
CreateMap<ContentUpdateDto, Content>(MemberList.Source);
CreateMap<BlogPost, BlogPostDto>(MemberList.Destination);
CreateMap<CreateUpdateBlogPostDto, BlogPost>(MemberList.Source);
CreateMap<Blog, BlogDto>(MemberList.Destination)
.ReverseMap();
CreateMap<Blog, BlogLookupDto>(MemberList.Destination);
CreateMap<TagEntityTypeDefiniton, TagDefinitionDto>(MemberList.Destination);
}
}

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

1
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs

@ -6,7 +6,6 @@ using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Domain.Volo.CmsKit.Contents;
using Volo.CmsKit.Permissions;
namespace Volo.CmsKit.Admin.Contents

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

68
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs

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

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

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

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
{

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

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

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

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

5
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs

@ -14,5 +14,10 @@
{
public const string UrlAlreadyExist = "CmsKit:Page:0001";
}
public static class Blogs
{
public const string SlugAlreadyExist = "CmsKit:BlogPost:0001";
}
}
}

17
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/BlogsFeature.cs

@ -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)
{
}
}
}

1
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs

@ -28,6 +28,7 @@ namespace Volo.CmsKit.GlobalFeatures
AddFeature(new TagsFeature(this));
AddFeature(new ContentsFeature(this));
AddFeature(new PagesFeature(this));
AddFeature(new BlogsFeature(this));
}
}
}

16
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json

@ -3,10 +3,14 @@
"texts": {
"CmsKit:0002": "Content already exists!",
"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",
@ -17,16 +21,17 @@
"Permission:Contents.Create": "Create Content",
"Permission:Contents.Delete": "Delete Content",
"Permission:Contents.Update": "Update Content",
"Permission:TagManagement": "Tag Management",
"Permission:TagManagement.Create": "Create",
"Permission:TagManagement.Delete": "Delete",
"Permission:TagManagement.Update": "Update",
"Permission:PageManagement": "Page Management",
"Permission:PageManagement:Create": "Create",
"Permission:PageManagement:Delete": "Delete",
"Permission:PageManagement:Update": "Update",
"Permission:TagManagement": "Tag Management",
"Permission:TagManagement.Create": "Create",
"Permission:TagManagement.Delete": "Delete",
"Permission:TagManagement.Update": "Update",
"PickYourReaction": "Pick your reaction",
"RatingUndoMessage": "Your rating will be undo.",
"Read": "Read",
"Reply": "Reply",
"Send": "Send",
"Star": "Star",
@ -35,7 +40,6 @@
"Undo": "Undo",
"Update": "Update",
"YourComment": "Your comment",
"YourReply": "Your reply",
"CmsKit:Page:0001": "The given url ({0}) already exists."
"YourReply": "Your reply"
}
}

8
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json

@ -3,10 +3,14 @@
"texts": {
"CmsKit:0002": "İçerik zaten mevcut!",
"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",
@ -23,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",
@ -31,7 +36,6 @@
"Undo": "Geri al",
"Update": "Güncelle",
"YourComment": "Yorumunuz",
"YourReply": "Cevabınız",
"CmsKit:Page:0001": "Girilen url ({0}) kullanımdadır."
"YourReply": "Cevabınız"
}
}

8
modules/cms-kit/src/Volo.CmsKit.Domain/Volo.CmsKit.Domain.csproj

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\common.props" />
<Import Project="..\..\..\..\configureawait.props" />
@ -8,10 +8,16 @@
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Slugify.Core" Version="3.0.0" />
<PackageReference Include="Unidecode.NET" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Ddd.Domain\Volo.Abp.Ddd.Domain.csproj" />
<ProjectReference Include="..\Volo.CmsKit.Domain.Shared\Volo.CmsKit.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\..\modules\users\src\Volo.Abp.Users.Domain\Volo.Abp.Users.Domain.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj" />
</ItemGroup>
</Project>

41
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs

@ -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();
}
}
}

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

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

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

@ -0,0 +1,9 @@
using Volo.Abp.BlobStoring;
namespace Volo.CmsKit.Blogs
{
[BlobContainerName("blog-post-cover-images")]
public class BlogPostCoverImageContainer
{
}
}

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

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

31
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostSlugAlreadyExistException.cs

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

15
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Extensions/SlugExtensions.cs

@ -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());
}
}
}

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

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

21
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs

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

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

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

6
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.Options;
using Volo.Abp.BlobStoring;
using Microsoft.Extensions.Options;
using Volo.Abp.Domain;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Localization;
@ -15,7 +16,8 @@ namespace Volo.CmsKit
[DependsOn(
typeof(CmsKitDomainSharedModule),
typeof(AbpUsersDomainModule),
typeof(AbpDddDomainModule)
typeof(AbpDddDomainModule),
typeof(AbpBlobStoringModule)
)]
public class CmsKitDomainModule : AbpModule
{

2
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentManager.cs

@ -7,7 +7,7 @@ using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.CmsKit.Contents;
namespace Volo.CmsKit.Domain.Volo.CmsKit.Contents
namespace Volo.CmsKit.Contents
{
public class ContentManager : DomainService, IContentManager
{

2
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentManager.cs

@ -2,7 +2,7 @@
using System.Threading.Tasks;
using Volo.CmsKit.Contents;
namespace Volo.CmsKit.Domain.Volo.CmsKit.Contents
namespace Volo.CmsKit.Contents
{
public interface IContentManager
{

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

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

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

27
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs

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

3
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs

@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Pages;
@ -22,6 +23,8 @@ namespace Volo.CmsKit.EntityFrameworkCore
public DbSet<Tag> Tags { get; set; }
public DbSet<EntityTag> EntityTags { get; set; }
public DbSet<Page> Pages { get; set; }
public DbSet<Blog> Blogs { get; set; }
public DbSet<BlogPost> BlogPosts { get; set; }
public CmsKitDbContext(DbContextOptions<CmsKitDbContext> options)
: base(options)

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

@ -13,6 +13,7 @@ using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Pages;
using Volo.CmsKit.Ratings;
using Volo.CmsKit.Tags;
using Volo.CmsKit.Blogs;
namespace Volo.CmsKit.EntityFrameworkCore
{
@ -58,8 +59,8 @@ namespace Volo.CmsKit.EntityFrameworkCore
b.Property(x => x.EntityId).IsRequired().HasMaxLength(UserReactionConsts.MaxEntityIdLength);
b.Property(x => x.ReactionName).IsRequired().HasMaxLength(UserReactionConsts.MaxReactionNameLength);
b.HasIndex(x => new {x.TenantId, x.EntityType, x.EntityId, x.ReactionName});
b.HasIndex(x => new {x.TenantId, x.CreatorId, x.EntityType, x.EntityId, x.ReactionName});
b.HasIndex(x => new { x.TenantId, x.EntityType, x.EntityId, x.ReactionName });
b.HasIndex(x => new { x.TenantId, x.CreatorId, x.EntityType, x.EntityId, x.ReactionName });
});
}
else
@ -80,8 +81,8 @@ namespace Volo.CmsKit.EntityFrameworkCore
b.Property(x => x.Text).IsRequired().HasMaxLength(CommentConsts.MaxTextLength);
b.Property(x => x.RepliedCommentId);
b.HasIndex(x => new {x.TenantId, x.EntityType, x.EntityId});
b.HasIndex(x => new {x.TenantId, x.RepliedCommentId});
b.HasIndex(x => new { x.TenantId, x.EntityType, x.EntityId });
b.HasIndex(x => new { x.TenantId, x.RepliedCommentId });
});
}
else
@ -179,13 +180,47 @@ namespace Volo.CmsKit.EntityFrameworkCore
b.Property(x => x.Url).IsRequired().HasMaxLength(PageConsts.MaxUrlLength);
b.Property(x => x.Description).HasMaxLength(PageConsts.MaxDescriptionLength);
b.HasIndex(x => new {x.TenantId, x.Url});
b.HasIndex(x => new { x.TenantId, x.Url });
});
}
else
{
builder.Ignore<Page>();
}
if (GlobalFeatureManager.Instance.IsEnabled<BlogsFeature>())
{
builder.Entity<Blog>(b =>
{
b.ToTable(options.TablePrefix + "Blogs", options.Schema);
b.ConfigureByConvention();
b.Property(p => p.Name).IsRequired().HasMaxLength(BlogConsts.MaxNameLength);
b.Property(p => p.Slug).IsRequired().HasMaxLength(BlogConsts.MaxSlugLength);
});
builder.Entity<BlogPost>(b =>
{
b.ToTable(options.TablePrefix + "BlogPosts", options.Schema);
b.ConfigureByConvention();
b.Property(p => p.Title).IsRequired().HasMaxLength(BlogPostConsts.MaxTitleLength);
b.Property(p => p.Slug).IsRequired().HasMaxLength(BlogPostConsts.MaxSlugLength);
b.Property(p => p.ShortDescription).HasMaxLength(BlogPostConsts.MaxShortDescriptionLength);
b.HasIndex(x => new { x.Slug, x.BlogId });
});
}
else
{
builder.Ignore<Blog>();
builder.Ignore<BlogPost>();
}
}
}
}

3
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitEntityFrameworkCoreModule.cs

@ -2,6 +2,7 @@
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.Users.EntityFrameworkCore;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Pages;
@ -31,6 +32,8 @@ namespace Volo.CmsKit.EntityFrameworkCore
options.AddRepository<Tag, EfCoreTagRepository>();
options.AddRepository<EntityTag, EfCoreEntityTagRepository>();
options.AddRepository<Page, EfCorePageRepository>();
options.AddRepository<Blog, EfCoreBlogRepository>();
options.AddRepository<BlogPost, EfCoreBlogPostRepository>();
});
}
}

3
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs

@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Pages;
@ -22,5 +23,7 @@ namespace Volo.CmsKit.EntityFrameworkCore
DbSet<Tag> Tags { get; set; }
DbSet<EntityTag> EntityTags { get; set; }
DbSet<Page> Pages { get; set; }
DbSet<Blog> Blogs { get; set; }
DbSet<BlogPost> BlogPosts { get; set; }
}
}

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,

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

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

28
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs

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

5
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContext.cs

@ -3,6 +3,7 @@ using Volo.Abp.Data;
using Volo.Abp.MongoDB;
using Volo.CmsKit.Comments;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Pages;
using Volo.CmsKit.Ratings;
using Volo.CmsKit.Reactions;
@ -31,6 +32,10 @@ namespace Volo.CmsKit.MongoDB
public IMongoCollection<Page> Pages => Collection<Page>();
public IMongoCollection<Blog> Blogs => Collection<Blog>();
public IMongoCollection<BlogPost> BlogPosts => Collection<BlogPost>();
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);

11
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContextExtensions.cs

@ -3,6 +3,7 @@ using Volo.Abp;
using Volo.Abp.MongoDB;
using Volo.CmsKit.Comments;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Pages;
using Volo.CmsKit.Ratings;
using Volo.CmsKit.Reactions;
@ -64,6 +65,16 @@ namespace Volo.CmsKit.MongoDB
{
x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Pages";
});
builder.Entity<Blog>(x =>
{
x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Blogs";
});
builder.Entity<BlogPost>(x =>
{
x.CollectionName = CmsKitDbProperties.DbTablePrefix + "BlogPosts";
});
}
}
}

4
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbModule.cs

@ -2,8 +2,10 @@
using Volo.Abp.Modularity;
using Volo.Abp.MongoDB;
using Volo.Abp.Users.MongoDB;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments;
using Volo.CmsKit.Contents;
using Volo.CmsKit.MongoDB.Blogs;
using Volo.CmsKit.MongoDB.Comments;
using Volo.CmsKit.MongoDB.Contents;
using Volo.CmsKit.MongoDB.Pages;
@ -38,6 +40,8 @@ namespace Volo.CmsKit.MongoDB
options.AddRepository<Tag, MongoTagRepository>();
options.AddRepository<EntityTag, MongoEntityTagRepository>();
options.AddRepository<Page, MongoPageRepository>();
options.AddRepository<Blog, MongoBlogRepository>();
options.AddRepository<BlogPost, MongoBlogPostRepository>();
});
}
}

15
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/ICmsKitMongoDbContext.cs

@ -3,6 +3,7 @@ using Volo.Abp.Data;
using Volo.Abp.MongoDB;
using Volo.CmsKit.Comments;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Pages;
using Volo.CmsKit.Ratings;
using Volo.CmsKit.Reactions;
@ -20,15 +21,19 @@ namespace Volo.CmsKit.MongoDB
IMongoCollection<Comment> Comments { get; }
IMongoCollection<CmsUser> CmsUsers { get; }
IMongoCollection<Rating> Ratings { get; }
IMongoCollection<Content> Contents { get; }
IMongoCollection<Tag> Tags { get; }
IMongoCollection<EntityTag> EntityTags { get; }
IMongoCollection<Page> Pages { get; }
IMongoCollection<Blog> Blogs { get; }
IMongoCollection<BlogPost> BlogPosts { get; }
}
}

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 Slug { 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 blogSlug, PagedAndSortedResultRequestDto input);
Task<BlogPostPublicDto> GetAsync(string blogSlug, string blogPostSlug);
Task<RemoteStreamContent> GetCoverImageAsync(Guid id);
}
}

56
modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs

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

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

55
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs

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

4
modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs

@ -61,10 +61,6 @@ namespace Volo.CmsKit.Public.Web
{
Configure<RazorPagesOptions>(options =>
{
if (GlobalFeatureManager.Instance.IsEnabled<PagesFeature>())
{
options.Conventions.AddPageRoute("/CmsKit/Pages/Index", @"{*pageUrl:minlength(1)}");
}
});
}
}

37
modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/PageController.cs

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

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

@ -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()
})
}

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

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

@ -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>

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

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

@ -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
})

34
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml.cs

@ -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();
}
}
}

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

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 blogSlug, string blogPostSlug)
{
var blogPost = await BlogPostPublicAppService.GetAsync(blogSlug, blogPostSlug);
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"
}
}
}

9
modules/cms-kit/src/Volo.CmsKit.Public.Web/Views/Page/Index.cshtml

@ -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
})

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

@ -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
}
}

BIN
modules/cms-kit/test/Volo.CmsKit.Application.Tests/Data/BlogPostSample.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

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,6 +5,10 @@
<RootNamespace>Volo.CmsKit</RootNamespace>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Data\**\*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.CmsKit.Application\Volo.CmsKit.Application.csproj" />
<ProjectReference Include="..\Volo.CmsKit.Domain.Tests\Volo.CmsKit.Domain.Tests.csproj" />

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

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

140
modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Blogs/SlugExtensions_Tests.cs

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

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

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

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

@ -5,9 +5,11 @@ using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Users;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Pages;
@ -30,7 +32,10 @@ namespace Volo.CmsKit
private readonly IContentRepository _contentRepository;
private readonly IEntityTagManager _entityTagManager;
private readonly ITagManager _tagManager;
private readonly IEntityTagRepository _entityTagRepository;
private readonly IPageRepository _pageRepository;
private readonly IBlogRepository _blogRepository;
private readonly IBlogPostRepository _blogPostRepository;
private readonly IOptions<CmsKitOptions> _options;
private readonly IOptions<CmsKitTagOptions> _tagOptions;
@ -44,8 +49,11 @@ namespace Volo.CmsKit
ICurrentTenant currentTenant,
IContentRepository contentRepository,
ITagManager tagManager,
IEntityTagManager entityTagManager,
IEntityTagRepository entityTagRepository,
IPageRepository pageRepository,
IBlogRepository blogRepository,
IBlogPostRepository blogPostRepository,
IEntityTagManager entityTagManager,
IOptions<CmsKitOptions> options,
IOptions<CmsKitTagOptions> tagOptions)
{
@ -59,7 +67,10 @@ namespace Volo.CmsKit
_contentRepository = contentRepository;
_tagManager = tagManager;
_entityTagManager = entityTagManager;
_entityTagRepository = entityTagRepository;
_pageRepository = pageRepository;
_blogRepository = blogRepository;
_blogPostRepository = blogPostRepository;
_options = options;
_tagOptions = tagOptions;
}
@ -83,6 +94,8 @@ namespace Volo.CmsKit
await SeedTagsAsync();
await SeedPagesAsync();
await SeedBlogsAsync();
}
}
@ -292,5 +305,14 @@ namespace Volo.CmsKit
await _pageRepository.InsertAsync(page2);
await _contentRepository.InsertAsync(page2Content);
}
private async Task SeedBlogsAsync()
{
var blog = await _blogRepository.InsertAsync(new Blog(_cmsKitTestData.Blog_Id, _cmsKitTestData.BlogName, _cmsKitTestData.BlogSlug));
await _blogPostRepository.InsertAsync(new BlogPost(_cmsKitTestData.BlogPost_1_Id, blog.Id, _cmsKitTestData.BlogPost_1_Title, _cmsKitTestData.BlogPost_1_Slug, "Short desc 1"));
await _blogPostRepository.InsertAsync(new BlogPost(_cmsKitTestData.BlogPost_2_Id, blog.Id, _cmsKitTestData.BlogPost_2_Title, _cmsKitTestData.BlogPost_2_Slug, "Short desc 2"));
}
}
}

53
modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitFakeCurrentUser.cs

@ -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();
}
}
}

1
modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestBase.cs

@ -5,6 +5,7 @@ using Volo.Abp;
using Volo.Abp.Modularity;
using Volo.Abp.Uow;
using Volo.Abp.Testing;
using Volo.Abp.GlobalFeatures;
namespace Volo.CmsKit
{

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save