Browse Source

merge from dev

pull/12087/head
enisn 4 years ago
parent
commit
ec47abd3e0
  1. 2
      README.md
  2. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  3. 7
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  4. 2
      docs/en/AspNet-Boilerplate-Migration-Guide.md
  5. 30
      docs/en/Distributed-Locking.md
  6. 2
      docs/en/UI/Angular/Theming.md
  7. 14
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs
  8. 3
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs
  9. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js
  10. 1
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs
  11. 10
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs
  12. 4
      framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs
  13. 15
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs
  14. 4
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs
  15. 11
      framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqConsts.cs
  16. 56
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs
  17. 12
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs
  18. 16
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs
  19. 20
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json
  20. 18
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml
  21. 14
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js
  22. 17
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/BlogPostScrollIndexFeature.cs
  23. 3
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs
  24. 8
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json
  25. 8
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json
  26. 11
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs
  27. 29
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs
  28. 31
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs
  29. 8
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostFilteredPagedAndSortedResultRequestDto.cs
  30. 7
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs
  31. 19
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs
  32. 18
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs
  33. 27
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.Generated.cs
  34. 7
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.cs
  35. 190
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json
  36. 11
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs
  37. 197
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml
  38. 30
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml
  39. 14
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs
  40. 17
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogPost.css
  41. 46
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogpost-scroll-index.js
  42. 60
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.css
  43. 168
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.js
  44. 22
      modules/cms-kit/src/Volo.CmsKit.Public.Web/wwwroot/client-proxies/cms-kit-proxy.js
  45. 2
      modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs
  46. 2
      npm/ng-packs/packages/core/src/lib/models/environment.ts

2
README.md

@ -110,7 +110,7 @@ Love ABP Framework? **Please give a star** to this repository :star:
## Discord Channel
You can use this link to join the ABP Community Discord Server: https://discord.gg/uVGt6hyhcm
You can use this link to join the ABP Community Discord Server: https://discord.gg/abp
## ABP Commercial

3
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json

@ -380,6 +380,7 @@
"PurchaseItems": "Purchase Items",
"SuccessfullyUpdated": "Successfully updated",
"SuccessfullyAdded": "Successfully added",
"PurchaseState": "Purchase State"
"PurchaseState": "Purchase State",
"ShowBetweenDayCount": "Show Between Days"
}
}

7
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -495,7 +495,9 @@
"LicenseTypeNotCorrect": "The license type is not correct!",
"Trainings": "Trainings",
"ChoseTrainingPlaceholder": "Chose the training...",
"ContactUsToGetQuote": "Contact us to get a quote",
"DoYouNeedTrainings": "Do you need one of these trainings?",
"DoYouNeedTraining": "Do you need {0} training?",
"GetInTouchUs": "Get in touch with us",
"ForMoreInformationClickHere": "For more information, click <a href='{0}'>here.</a>",
"IsGetOnboardingTraining": "Would you like to get onboarding & web application development training?",
"OnboardingWebApplicationDevelopmentTrainingMessage": "To schedule your training calendar, please contact {0} after creating the organization",
@ -503,6 +505,7 @@
"AdditionalNote": "Additional Note",
"OnboardingTrainingFaqTitle": "Do you have ABP onboarding training?",
"OnboardingTrainingFaqExplanation": "Yes, we have ABP Training Services to help you get your ABP project started fast. You will learn about ABP from an ABP core team member and you will get the skills to begin your ABP project. In the onboarding training, we will explain how to set up your development environment, install the required tools, create a fully functional CRUD page. The training will be live and the Zoom application will be used, and we are open to using other online meeting platforms. The language of the training will be English. You can also ask your questions about ABP during the sessions. A convenient time and date will be planned for both parties. To get more information, contact us at <a href=\"mailto:info@abp.io\">info@abp.io</a>.",
"AddBasket": "Add to Basket"
"AddBasket": "Add to Basket",
"SendTrainingRequest": "Send Training Request"
}
}

2
docs/en/AspNet-Boilerplate-Migration-Guide.md

@ -1,4 +1,4 @@
# ASP.NET Boilerplate v5+ to ABP Framework Migration
# Migrating from ASP.NET Boilerplate to the ABP Framework
ABP Framework is **the successor** of the open source [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework. This guide aims to help you to **migrate your existing solutions** (you developed with the ASP.NET Boilerplate framework) to the ABP Framework.

30
docs/en/Distributed-Locking.md

@ -27,21 +27,25 @@ using Medallion.Threading.Redis;
namespace AbpDemo
{
public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
context.Services.AddSingleton<IDistributedLockProvider>(sp =>
{
var connection = ConnectionMultiplexer
[DependsOn(
typeof(AbpDistributedLockingModule)
//If you have the other dependencies, you should do here
)]
public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
context.Services.AddSingleton<IDistributedLockProvider>(sp =>
{
var connection = ConnectionMultiplexer
.Connect(configuration["Redis:Configuration"]);
return new
return new
RedisDistributedSynchronizationProvider(connection.GetDatabase());
});
}
}
});
}
}
}
````

2
docs/en/UI/Angular/Theming.md

@ -227,7 +227,7 @@ import { Router } from '@angular/router';
template: `
<a class="dropdown-item pointer" (click)="data.action()">
<i *ngIf="data.textTemplate.icon" [class]="data.textTemplate.icon"></i>
{{ data.textTemplate.text | abpLocalization }}
{%{{{ data.textTemplate.text | abpLocalization }}}%}
</a>
`,
})

14
framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs

@ -13,6 +13,20 @@ public static class AbpClaimActionCollectionExtensions
claimActions.DeleteClaim("name");
claimActions.RemoveDuplicate(AbpClaimTypes.UserName);
}
if (AbpClaimTypes.Name != "given_name")
{
claimActions.MapJsonKey(AbpClaimTypes.Name, "given_name");
claimActions.DeleteClaim("given_name");
claimActions.RemoveDuplicate(AbpClaimTypes.Name);
}
if (AbpClaimTypes.SurName != "family_name")
{
claimActions.MapJsonKey(AbpClaimTypes.SurName, "family_name");
claimActions.DeleteClaim("family_name");
claimActions.RemoveDuplicate(AbpClaimTypes.SurName);
}
if (AbpClaimTypes.Email != "email")
{

3
framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs

@ -57,8 +57,7 @@ public static class AbpOpenIdConnectExtensions
if (receivedContext.Request.Cookies.ContainsKey(tenantKey))
{
receivedContext.TokenEndpointRequest.SetParameter(tenantKey,
receivedContext.Request.Cookies[tenantKey]);
receivedContext.TokenEndpointRequest?.SetParameter(tenantKey, receivedContext.Request.Cookies[tenantKey]);
}
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js

@ -431,9 +431,7 @@ var abp = abp || {};
configuration.language = datatables.defaultConfigurations.language();
if(configuration.dom){
configuration.dom += datatables.defaultConfigurations.dom;
}else{
if(!configuration.dom){
configuration.dom = datatables.defaultConfigurations.dom;
}

1
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs

@ -82,6 +82,7 @@ public class AbpExceptionHandlingMiddleware : IMiddleware, ITransientDependency
httpContext.Response.StatusCode = (int)statusCodeFinder.GetStatusCode(httpContext, exception);
httpContext.Response.OnStarting(_clearCacheHeadersDelegate, httpContext.Response);
httpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
httpContext.Response.Headers.Add("Content-Type", "application/json");
await httpContext.Response.WriteAsync(
jsonSerializer.Serialize(

10
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs

@ -81,12 +81,12 @@ public class DatabaseManagementSystemChangeStep : ProjectBuildPipelineStep
private void ChangeEntityFrameworkCoreDependency(ProjectBuildContext context, string newPackageName, string newModuleNamespace, string newModuleClass)
{
var efCoreProjectFile = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCore.csproj", StringComparison.OrdinalIgnoreCase));
efCoreProjectFile.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newPackageName);
var efCoreProjectFile = context.Files.FirstOrDefault(f => f.Name.EndsWith("EntityFrameworkCore.csproj", StringComparison.OrdinalIgnoreCase));
efCoreProjectFile?.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newPackageName);
var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase));
efCoreModuleClass.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newModuleNamespace);
efCoreModuleClass.ReplaceText("AbpEntityFrameworkCoreSqlServerModule", newModuleClass);
var efCoreModuleClass = context.Files.FirstOrDefault(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase));
efCoreModuleClass?.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newModuleNamespace);
efCoreModuleClass?.ReplaceText("AbpEntityFrameworkCoreSqlServerModule", newModuleClass);
}
private void ChangeUseSqlServer(ProjectBuildContext context, string newUseMethodForEfModule, string newUseMethodForDbContext = null)

4
framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs

@ -57,8 +57,6 @@ public static class CultureHelper
public static string GetBaseCultureName(string cultureName)
{
return cultureName.Contains("-")
? cultureName.Left(cultureName.IndexOf("-", StringComparison.Ordinal))
: cultureName;
return new CultureInfo(cultureName).Parent.Name;
}
}

15
framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs

@ -1,10 +1,23 @@
namespace Volo.Abp.EventBus.RabbitMq;
using Volo.Abp.RabbitMQ;
namespace Volo.Abp.EventBus.RabbitMq;
public class AbpRabbitMqEventBusOptions
{
public const string DefaultExchangeType = RabbitMqConsts.ExchangeTypes.Direct;
public string ConnectionName { get; set; }
public string ClientName { get; set; }
public string ExchangeName { get; set; }
public string ExchangeType { get; set; }
public string GetExchangeTypeOrDefault()
{
return string.IsNullOrEmpty(ExchangeType)
? DefaultExchangeType
: ExchangeType;
}
}

4
framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs

@ -69,7 +69,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
Consumer = MessageConsumerFactory.Create(
new ExchangeDeclareConfiguration(
AbpRabbitMqEventBusOptions.ExchangeName,
type: "direct",
type: AbpRabbitMqEventBusOptions.GetExchangeTypeOrDefault(),
durable: true
),
new QueueDeclareConfiguration(
@ -244,7 +244,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
{
channel.ExchangeDeclare(
AbpRabbitMqEventBusOptions.ExchangeName,
"direct",
AbpRabbitMqEventBusOptions.GetExchangeTypeOrDefault(),
durable: true
);

11
framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqConsts.cs

@ -8,4 +8,15 @@ public static class RabbitMqConsts
public const int Persistent = 2;
}
public static class ExchangeTypes
{
public const string Direct = "direct";
public const string Topic = "topic";
public const string Fanout = "fanout";
public const string Headers = "headers";
}
}

56
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs

@ -1,4 +1,4 @@
using System.Globalization;
using System.Globalization;
using System.Linq;
using Microsoft.Extensions.Localization;
using Shouldly;
@ -183,6 +183,60 @@ public class AbpLocalization_Tests : AbpIntegratedTest<AbpLocalization_Tests.Tes
{
_localizer["CarPlural"].Value.ShouldBe("Autos");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hans")))
{
_localizer["Car"].Value.ShouldBe("汽车");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hans")))
{
_localizer["CarPlural"].Value.ShouldBe("汽车");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-CN")))
{
_localizer["Car"].Value.ShouldBe("汽车");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-CN")))
{
_localizer["CarPlural"].Value.ShouldBe("汽车");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hans-CN")))
{
_localizer["Car"].Value.ShouldBe("汽车");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hans-CN")))
{
_localizer["CarPlural"].Value.ShouldBe("汽车");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hant")))
{
_localizer["Car"].Value.ShouldBe("汽車");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hant")))
{
_localizer["CarPlural"].Value.ShouldBe("汽車");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-TW")))
{
_localizer["Car"].Value.ShouldBe("汽車");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-TW")))
{
_localizer["CarPlural"].Value.ShouldBe("汽車");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hant-TW")))
{
_localizer["Car"].Value.ShouldBe("汽車");
}
using (CultureHelper.Use(CultureInfo.GetCultureInfo("zh-Hant-TW")))
{
_localizer["CarPlural"].Value.ShouldBe("汽車");
}
}
[Fact]

12
modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs

@ -277,6 +277,18 @@ public class LoginModel : AccountPageModel
CheckIdentityErrors(await UserManager.SetEmailAsync(user, emailAddress));
CheckIdentityErrors(await UserManager.AddLoginAsync(user, info));
CheckIdentityErrors(await UserManager.AddDefaultRolesAsync(user));
user.Name = info.Principal.FindFirstValue(AbpClaimTypes.Name);
user.Surname = info.Principal.FindFirstValue(AbpClaimTypes.SurName);
var phoneNumber = info.Principal.FindFirstValue(AbpClaimTypes.PhoneNumber);
if (!phoneNumber.IsNullOrWhiteSpace())
{
var phoneNumberConfirmed = string.Equals(info.Principal.FindFirstValue(AbpClaimTypes.PhoneNumberVerified), "true", StringComparison.InvariantCultureIgnoreCase);
user.SetPhoneNumber(phoneNumber, phoneNumberConfirmed);
}
await UserManager.UpdateAsync(user);
return user;
}

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

@ -6,6 +6,7 @@ using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Users;
using Volo.CmsKit.Admin.MediaDescriptors;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Permissions;
@ -22,16 +23,20 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe
protected IBlogRepository BlogRepository { get; }
protected ICmsUserLookupService UserLookupService { get; }
protected IMediaDescriptorAdminAppService MediaDescriptorAdminAppService { get; }
public BlogPostAdminAppService(
BlogPostManager blogPostManager,
IBlogPostRepository blogPostRepository,
IBlogRepository blogRepository,
ICmsUserLookupService userLookupService)
ICmsUserLookupService userLookupService,
IMediaDescriptorAdminAppService mediaDescriptorAdminAppService)
{
BlogPostManager = blogPostManager;
BlogPostRepository = blogPostRepository;
BlogRepository = blogRepository;
UserLookupService = userLookupService;
MediaDescriptorAdminAppService = mediaDescriptorAdminAppService;
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)]
@ -61,13 +66,18 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe
public virtual async Task<BlogPostDto> UpdateAsync(Guid id, UpdateBlogPostDto input)
{
var blogPost = await BlogPostRepository.GetAsync(id);
blogPost.SetTitle(input.Title);
blogPost.SetShortDescription(input.ShortDescription);
blogPost.SetContent(input.Content);
blogPost.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp);
if (blogPost.CoverImageMediaId != null && input.CoverImageMediaId == null)
{
await MediaDescriptorAdminAppService.DeleteAsync(blogPost.CoverImageMediaId.Value);
}
blogPost.CoverImageMediaId = input.CoverImageMediaId;
if (blogPost.Slug != input.Slug)
{
await BlogPostManager.SetSlugUrlAsync(blogPost, input.Slug);

20
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json

@ -7,6 +7,8 @@
"Volo.CmsKit.Admin.Tags.EntityTagAdminController": {
"controllerName": "EntityTagAdmin",
"controllerGroupName": "EntityTagAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.Tags.EntityTagAdminController",
"interfaces": [
{
@ -154,6 +156,8 @@
"Volo.CmsKit.Admin.Tags.TagAdminController": {
"controllerName": "TagAdmin",
"controllerGroupName": "TagAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.Tags.TagAdminController",
"interfaces": [
{
@ -422,6 +426,8 @@
"Volo.CmsKit.Admin.Pages.PageAdminController": {
"controllerName": "PageAdmin",
"controllerGroupName": "PageAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.Pages.PageAdminController",
"interfaces": [
{
@ -675,6 +681,8 @@
"Volo.CmsKit.Admin.Menus.MenuItemAdminController": {
"controllerName": "MenuItemAdmin",
"controllerGroupName": "MenuItemAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.Menus.MenuItemAdminController",
"interfaces": [
{
@ -1000,6 +1008,8 @@
"Volo.CmsKit.Admin.MediaDescriptors.MediaDescriptorAdminController": {
"controllerName": "MediaDescriptorAdmin",
"controllerGroupName": "MediaDescriptorAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.MediaDescriptors.MediaDescriptorAdminController",
"interfaces": [
{
@ -1118,6 +1128,8 @@
"Volo.CmsKit.Admin.GlobalResources.GlobalResourceAdminController": {
"controllerName": "GlobalResourceAdmin",
"controllerGroupName": "GlobalResourceAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.GlobalResources.GlobalResourceAdminController",
"interfaces": [
{
@ -1182,6 +1194,8 @@
"Volo.CmsKit.Admin.Comments.CommentAdminController": {
"controllerName": "CommentAdmin",
"controllerGroupName": "CommentAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.Comments.CommentAdminController",
"interfaces": [
{
@ -1401,6 +1415,8 @@
"Volo.CmsKit.Admin.Blogs.BlogAdminController": {
"controllerName": "BlogAdmin",
"controllerGroupName": "BlogAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.Blogs.BlogAdminController",
"interfaces": [
{
@ -1654,6 +1670,8 @@
"Volo.CmsKit.Admin.Blogs.BlogFeatureAdminController": {
"controllerName": "BlogFeatureAdmin",
"controllerGroupName": "BlogFeatureAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.Blogs.BlogFeatureAdminController",
"interfaces": [
{
@ -1760,6 +1778,8 @@
"Volo.CmsKit.Admin.Blogs.BlogPostAdminController": {
"controllerName": "BlogPostAdmin",
"controllerGroupName": "BlogPostAdmin",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Admin.Blogs.BlogPostAdminController",
"interfaces": [
{

18
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml

@ -48,13 +48,17 @@
<abp-card-body>
<div class="mb-3">
@if (Model.ViewModel.CoverImageMediaId != null)
{
<img height="120" src="/api/cms-kit/media/@Model.ViewModel.CoverImageMediaId" />
<br />
}
<label class="form-label" >@L["CoverImage"]</label>
<input type="file" id="BlogPostCoverImage" class="form-control" />
<div id="CurrentCoverImageArea">
@if (Model.ViewModel.CoverImageMediaId != null)
{
<img height="120" src="/api/cms-kit/media/@Model.ViewModel.CoverImageMediaId"/>
<br/>
<abp-button button-type="Link" type="button" text="@L["RemoveCoverImage"].Value" id="button-remove-cover-image"/>
<br/>
}
</div>
<label class="form-label">@L["CoverImage"]</label>
<input type="file" id="BlogPostCoverImage" class="form-control"/>
</div>
<abp-dynamic-form abp-model="ViewModel" asp-page="/CmsKit/BlogPosts/Update" id="form-blog-post-update">

14
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js

@ -10,6 +10,7 @@ $(function () {
var $blogPostIdInput = $('#Id');
var $tagsInput = $('.tag-editor-form input[name=tags]');
var $fileInput = $('#BlogPostCoverImage');
var $buttonRemoveCoverImage = $('#button-remove-cover-image');
var UPPY_FILE_ID = "uppy-upload-file";
@ -152,7 +153,6 @@ $(function () {
}
}
// -----------------------------------
var fileUploadUri = "/api/cms-kit-admin/media/blogpost";
var fileUriPrefix = "/api/cms-kit/media/";
@ -225,4 +225,16 @@ $(function () {
}
});
}
$buttonRemoveCoverImage.on('click', function () {
abp.message.confirm(
l('RemoveCoverImageConfirmationMessage'),
function (isConfirmed) {
if (isConfirmed) {
$coverImage.val(null);
$('#CurrentCoverImageArea').remove();
}
}
);
});
});

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

@ -0,0 +1,17 @@
using JetBrains.Annotations;
using Volo.Abp.GlobalFeatures;
namespace Volo.CmsKit.GlobalFeatures;
[GlobalFeatureName(Name)]
public class BlogPostScrollIndexFeature : GlobalFeature
{
public const string Name = "CmsKit.BlogPost.ScrollIndex";
internal BlogPostScrollIndexFeature(
[NotNull] GlobalCmsKitFeatures cmsKit
) : base(cmsKit)
{
}
}

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

@ -26,6 +26,8 @@ public class GlobalCmsKitFeatures : GlobalModuleFeatures
public MenuFeature Menu => GetFeature<MenuFeature>();
public GlobalResourcesFeature GlobalResources => GetFeature<GlobalResourcesFeature>();
public BlogPostScrollIndexFeature BlogPostScrollIndex => GetFeature<BlogPostScrollIndexFeature>();
public GlobalCmsKitFeatures([NotNull] GlobalFeatureManager featureManager)
: base(featureManager)
@ -40,5 +42,6 @@ public class GlobalCmsKitFeatures : GlobalModuleFeatures
AddFeature(new CmsUserFeature(this));
AddFeature(new MenuFeature(this));
AddFeature(new GlobalResourcesFeature(this));
AddFeature(new BlogPostScrollIndexFeature(this));
}
}

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

@ -131,6 +131,7 @@
"SelectAll": "Select All",
"Send": "Send",
"SendMessage": "Send Message",
"SelectedAuthor": "Author",
"ShortDescription": "Short description",
"Slug": "Slug",
"Source": "Source",
@ -182,6 +183,11 @@
"HasBlogPostWaitingForReviewMessage": "You have a blog post waiting for review. Click to list.",
"SelectAStatus": "Select a status",
"Status": "Status",
"SelectAnAuthor": "Select an author"
"SelectAnAuthor": "Select an author",
"SavedSuccessfully": "Saved successfully",
"GoToTop": "Go to top",
"InThisDocument": "In this document",
"RemoveCoverImageConfirmationMessage": "Are you sure to remove the cover image?",
"RemoveCoverImage": "Remove the cover image"
}
}

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

@ -130,6 +130,7 @@
"SelectAll": "Hepsini seç",
"Send": "Gönder",
"SendMessage": "Mesajı Gönder",
"SelectedAuthor": "Yazar",
"ShortDescription": "Kısa açıklama",
"Slug": "Etiket",
"Source": "Kaynak",
@ -181,6 +182,11 @@
"HasBlogPostWaitingForReviewMessage": "Yayınlanmak için onay bekleyen blog postlar var! Listelemek için tıklayın.",
"SelectAStatus": "Durum seçin",
"Status": "Durum",
"SelectAnAuthor": "Bir yazar seçin"
"SelectAnAuthor": "Bir yazar seçin",
"SavedSuccessfully": "Başarıyla kaydedildi",
"GoToTop": "Yukarı Git",
"InThisDocument": "Bu belgede",
"RemoveCoverImageConfirmationMessage": "Kapak resmini kaldırmak istediğinize emin misiniz?",
"RemoveCoverImage": "Kapak resmini kaldır"
}
}

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

@ -30,7 +30,16 @@ public interface IBlogPostRepository : IBasicRepository<BlogPost, Guid>
Task<BlogPost> GetBySlugAsync(Guid blogId, string slug, CancellationToken cancellationToken = default);
Task<List<CmsUser>> GetAuthorsHasBlogPosts(CancellationToken cancellationToken = default);
Task<List<CmsUser>> GetAuthorsHasBlogPostsAsync(
int skipCount,
int maxResultCount,
string sorting,
string filter,
CancellationToken cancellationToken = default);
Task<int> GetAuthorsHasBlogPostsCountAsync(string filter, CancellationToken cancellationToken = default);
Task<CmsUser> GetAuthorHasBlogPostAsync(Guid id, CancellationToken cancellationToken = default);
Task<bool> HasBlogPostWaitingForReviewAsync(CancellationToken cancellationToken = default);
}

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

@ -7,6 +7,7 @@ using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.CmsKit.EntityFrameworkCore;
@ -104,13 +105,33 @@ public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPo
GetCancellationToken(cancellationToken));
}
public async Task<List<CmsUser>> GetAuthorsHasBlogPosts(CancellationToken cancellationToken = default)
public async Task<List<CmsUser>> GetAuthorsHasBlogPostsAsync(int skipCount, int maxResultCount, string sorting, string filter, CancellationToken cancellationToken = default)
{
return await (await GetDbContextAsync()).BlogPosts
.Where(x => x.Status == BlogPostStatus.Published)
.Select(x => x.Author).Distinct()
return await (await CreateAuthorsQueryableAsync())
.Skip(skipCount)
.Take(maxResultCount)
.WhereIf(!filter.IsNullOrEmpty(), x => x.UserName.Contains(filter.ToLower()))
.OrderBy(sorting.IsNullOrEmpty() ? nameof(CmsUser.UserName) : sorting)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<int> GetAuthorsHasBlogPostsCountAsync(string filter, CancellationToken cancellationToken = default)
{
return await (await CreateAuthorsQueryableAsync())
.WhereIf(!filter.IsNullOrEmpty(), x => x.UserName.Contains(filter.ToLower()))
.CountAsync(GetCancellationToken(cancellationToken));
}
public async Task<CmsUser> GetAuthorHasBlogPostAsync(Guid id, CancellationToken cancellationToken = default)
{
return await (await CreateAuthorsQueryableAsync()).FirstOrDefaultAsync(x => x.Id == id, GetCancellationToken(cancellationToken))
?? throw new EntityNotFoundException(typeof(CmsUser), id);
}
private async Task<IQueryable<CmsUser>> CreateAuthorsQueryableAsync()
{
return (await GetDbContextAsync()).BlogPosts.Select(x => x.Author).Distinct();
}
public virtual async Task<bool> HasBlogPostWaitingForReviewAsync(CancellationToken cancellationToken = default)
{

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

@ -8,6 +8,7 @@ using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;
using Volo.CmsKit.Blogs;
@ -108,7 +109,31 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
return await queryable.AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug, cancellationToken);
}
public async Task<List<CmsUser>> GetAuthorsHasBlogPosts(CancellationToken cancellationToken = default)
public async Task<List<CmsUser>> GetAuthorsHasBlogPostsAsync(int skipCount, int maxResultCount, string sorting, string filter, CancellationToken cancellationToken = default)
{
var queryable = (await CreateAuthorsQueryableAsync())
.Skip(skipCount)
.Take(maxResultCount)
.OrderBy(sorting.IsNullOrEmpty() ? nameof(CmsUser.UserName) : sorting)
.WhereIf(!filter.IsNullOrEmpty(), x => x.UserName.Contains(filter.ToLower()));
return await AsyncExecuter.ToListAsync(queryable, GetCancellationToken(cancellationToken));
}
public async Task<int> GetAuthorsHasBlogPostsCountAsync(string filter, CancellationToken cancellationToken = default)
{
return await AsyncExecuter.CountAsync(
(await CreateAuthorsQueryableAsync())
.WhereIf(!filter.IsNullOrEmpty(), x => x.UserName.Contains(filter.ToLower())));
}
public async Task<CmsUser> GetAuthorHasBlogPostAsync(Guid id, CancellationToken cancellationToken = default)
{
return await AsyncExecuter.FirstOrDefaultAsync(await CreateAuthorsQueryableAsync(), x => x.Id == id)
?? throw new EntityNotFoundException(typeof(CmsUser), id);
}
private async Task<IQueryable<CmsUser>> CreateAuthorsQueryableAsync()
{
cancellationToken = GetCancellationToken(cancellationToken);
@ -117,7 +142,7 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
var usersQueryable = (await GetDbContextAsync(cancellationToken)).Collection<CmsUser>().AsQueryable();
var queryable = blogPostQueryable
return blogPostQueryable
.Join(
usersQueryable,
o => o.AuthorId,
@ -125,8 +150,6 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
(blogPost, user) => new { blogPost, user })
.Select(s => s.user)
.Distinct();
return await AsyncExecuter.ToListAsync(queryable, cancellationToken);
}
public virtual async Task<bool> HasBlogPostWaitingForReviewAsync(CancellationToken cancellationToken = default)

8
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostFilteredPagedAndSortedResultRequestDto.cs

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

7
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs

@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Users;
using System;
namespace Volo.CmsKit.Public.Blogs;
@ -12,6 +13,8 @@ public interface IBlogPostPublicAppService : IApplicationService
Task<PagedResultDto<BlogPostPublicDto>> GetListAsync([NotNull] string blogSlug, BlogPostGetListInput input);
Task<BlogPostPublicDto> GetAsync([NotNull] string blogSlug, [NotNull] string blogPostSlug);
Task<List<CmsUserDto>> GetAuthorsHasBlogPostsAsync();
Task<PagedResultDto<CmsUserDto>> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input);
Task<CmsUserDto> GetAuthorHasBlogPostAsync(Guid id);
}

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

@ -1,4 +1,5 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
@ -15,7 +16,6 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub
protected IBlogRepository BlogRepository { get; }
protected IBlogPostRepository BlogPostRepository { get; }
public BlogPostPublicAppService(
IBlogRepository blogRepository,
@ -46,9 +46,20 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub
ObjectMapper.Map<List<BlogPost>, List<BlogPostPublicDto>>(blogPosts));
}
public virtual async Task<List<CmsUserDto>> GetAuthorsHasBlogPostsAsync()
public virtual async Task<PagedResultDto<CmsUserDto>> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input)
{
var authors = await BlogPostRepository.GetAuthorsHasBlogPosts();
return ObjectMapper.Map<List<CmsUser>, List<CmsUserDto>>(authors);
var authors = await BlogPostRepository.GetAuthorsHasBlogPostsAsync(input.SkipCount, input.MaxResultCount, input.Sorting, input.Filter);
var authorDtos = ObjectMapper.Map<List<CmsUser>, List<CmsUserDto>>(authors);
return new PagedResultDto<CmsUserDto>(
await BlogPostRepository.GetAuthorsHasBlogPostsCountAsync(input.Filter),
authorDtos);
}
public async Task<CmsUserDto> GetAuthorHasBlogPostAsync(Guid id)
{
var author = await BlogPostRepository.GetAuthorHasBlogPostAsync(id);
return ObjectMapper.Map<CmsUser, CmsUserDto>(author);
}
}

18
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs

@ -1,6 +1,5 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
@ -25,7 +24,7 @@ public partial class BlogPostPublicClientProxy : ClientProxyBase<IBlogPostPublic
{ typeof(string), blogPostSlug }
});
}
public virtual async Task<PagedResultDto<BlogPostPublicDto>> GetListAsync(string blogSlug, BlogPostGetListInput input)
{
return await RequestAsync<PagedResultDto<BlogPostPublicDto>>(nameof(GetListAsync), new ClientProxyRequestTypeValue
@ -35,8 +34,19 @@ public partial class BlogPostPublicClientProxy : ClientProxyBase<IBlogPostPublic
});
}
public virtual async Task<List<CmsUserDto>> GetAuthorsHasBlogPostsAsync()
public virtual async Task<PagedResultDto<CmsUserDto>> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input)
{
return await RequestAsync<PagedResultDto<CmsUserDto>>(nameof(GetAuthorsHasBlogPostsAsync), new ClientProxyRequestTypeValue
{
{ typeof(BlogPostFilteredPagedAndSortedResultRequestDto), input }
});
}
public virtual async Task<CmsUserDto> GetAuthorHasBlogPostAsync(Guid id)
{
return await RequestAsync<List<CmsUserDto>>(nameof(GetAuthorsHasBlogPostsAsync));
return await RequestAsync<CmsUserDto>(nameof(GetAuthorHasBlogPostAsync), new ClientProxyRequestTypeValue
{
{ typeof(Guid), id }
});
}
}

27
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.Generated.cs

@ -0,0 +1,27 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Public.GlobalResources;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.GlobalResources.ClientProxies;
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IGlobalResourcePublicAppService), typeof(GlobalResourcePublicClientProxy))]
public partial class GlobalResourcePublicClientProxy : ClientProxyBase<IGlobalResourcePublicAppService>, IGlobalResourcePublicAppService
{
public virtual async Task<GlobalResourceDto> GetGlobalScriptAsync()
{
return await RequestAsync<GlobalResourceDto>(nameof(GetGlobalScriptAsync));
}
public virtual async Task<GlobalResourceDto> GetGlobalStyleAsync()
{
return await RequestAsync<GlobalResourceDto>(nameof(GetGlobalStyleAsync));
}
}

7
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.cs

@ -0,0 +1,7 @@
// This file is part of GlobalResourcePublicClientProxy, you can customize it here
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.GlobalResources.ClientProxies;
public partial class GlobalResourcePublicClientProxy
{
}

190
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json

@ -7,6 +7,8 @@
"Volo.CmsKit.Public.Tags.TagPublicController": {
"controllerName": "TagPublic",
"controllerGroupName": "TagPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Tags.TagPublicController",
"interfaces": [
{
@ -76,6 +78,8 @@
"Volo.CmsKit.Public.Reactions.ReactionPublicController": {
"controllerName": "ReactionPublic",
"controllerGroupName": "ReactionPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Reactions.ReactionPublicController",
"interfaces": [
{
@ -299,6 +303,8 @@
"Volo.CmsKit.Public.Ratings.RatingPublicController": {
"controllerName": "RatingPublic",
"controllerGroupName": "RatingPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Ratings.RatingPublicController",
"interfaces": [
{
@ -502,6 +508,8 @@
"Volo.CmsKit.Public.Pages.PagesPublicController": {
"controllerName": "PagesPublic",
"controllerGroupName": "PagesPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Pages.PagesPublicController",
"interfaces": [
{
@ -551,6 +559,8 @@
"Volo.CmsKit.Public.Menus.MenuItemPublicController": {
"controllerName": "MenuItemPublic",
"controllerGroupName": "MenuItemPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Menus.MenuItemPublicController",
"interfaces": [
{
@ -575,9 +585,55 @@
}
}
},
"Volo.CmsKit.Public.GlobalResources.GlobalResourcePublicController": {
"controllerName": "GlobalResourcePublic",
"controllerGroupName": "GlobalResourcePublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.GlobalResources.GlobalResourcePublicController",
"interfaces": [
{
"type": "Volo.CmsKit.Public.GlobalResources.IGlobalResourcePublicAppService"
}
],
"actions": {
"GetGlobalScriptAsync": {
"uniqueName": "GetGlobalScriptAsync",
"name": "GetGlobalScriptAsync",
"httpMethod": "GET",
"url": "api/cms-kit-public/global-resources/script",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "Volo.CmsKit.Public.GlobalResources.GlobalResourceDto",
"typeSimple": "Volo.CmsKit.Public.GlobalResources.GlobalResourceDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.CmsKit.Public.GlobalResources.IGlobalResourcePublicAppService"
},
"GetGlobalStyleAsync": {
"uniqueName": "GetGlobalStyleAsync",
"name": "GetGlobalStyleAsync",
"httpMethod": "GET",
"url": "api/cms-kit-public/global-resources/style",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "Volo.CmsKit.Public.GlobalResources.GlobalResourceDto",
"typeSimple": "Volo.CmsKit.Public.GlobalResources.GlobalResourceDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.CmsKit.Public.GlobalResources.IGlobalResourcePublicAppService"
}
}
},
"Volo.CmsKit.Public.Comments.CommentPublicController": {
"controllerName": "CommentPublic",
"controllerGroupName": "CommentPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Comments.CommentPublicController",
"interfaces": [
{
@ -818,6 +874,8 @@
"Volo.CmsKit.Public.Blogs.BlogPostPublicController": {
"controllerName": "BlogPostPublic",
"controllerGroupName": "BlogPostPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Blogs.BlogPostPublicController",
"interfaces": [
{
@ -899,9 +957,9 @@
},
{
"name": "input",
"typeAsString": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto, Volo.Abp.Ddd.Application.Contracts",
"type": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto",
"typeSimple": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto",
"typeAsString": "Volo.CmsKit.Public.Blogs.BlogPostGetListInput, Volo.CmsKit.Public.Application.Contracts",
"type": "Volo.CmsKit.Public.Blogs.BlogPostGetListInput",
"typeSimple": "Volo.CmsKit.Public.Blogs.BlogPostGetListInput",
"isOptional": false,
"defaultValue": null
}
@ -919,6 +977,30 @@
"bindingSourceId": "Path",
"descriptorName": ""
},
{
"nameOnMethod": "input",
"name": "AuthorId",
"jsonName": null,
"type": "System.Guid?",
"typeSimple": "string?",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "Sorting",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "SkipCount",
@ -942,6 +1024,43 @@
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.PagedResultDto<Volo.CmsKit.Public.Blogs.BlogPostPublicDto>",
"typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto<Volo.CmsKit.Public.Blogs.BlogPostPublicDto>"
},
"allowAnonymous": null,
"implementFrom": "Volo.CmsKit.Public.Blogs.IBlogPostPublicAppService"
},
"GetAuthorsHasBlogPostsAsyncByInput": {
"uniqueName": "GetAuthorsHasBlogPostsAsyncByInput",
"name": "GetAuthorsHasBlogPostsAsync",
"httpMethod": "GET",
"url": "api/cms-kit-public/blog-posts/authors",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Volo.CmsKit.Public.Blogs.BlogPostFilteredPagedAndSortedResultRequestDto, Volo.CmsKit.Public.Application.Contracts",
"type": "Volo.CmsKit.Public.Blogs.BlogPostFilteredPagedAndSortedResultRequestDto",
"typeSimple": "Volo.CmsKit.Public.Blogs.BlogPostFilteredPagedAndSortedResultRequestDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "Filter",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
@ -954,11 +1073,72 @@
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "SkipCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "MaxResultCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.PagedResultDto<Volo.CmsKit.Public.Blogs.BlogPostPublicDto>",
"typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto<Volo.CmsKit.Public.Blogs.BlogPostPublicDto>"
"type": "Volo.Abp.Application.Dtos.PagedResultDto<Volo.CmsKit.Users.CmsUserDto>",
"typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto<Volo.CmsKit.Users.CmsUserDto>"
},
"allowAnonymous": null,
"implementFrom": "Volo.CmsKit.Public.Blogs.IBlogPostPublicAppService"
},
"GetAuthorHasBlogPostAsyncById": {
"uniqueName": "GetAuthorHasBlogPostAsyncById",
"name": "GetAuthorHasBlogPostAsync",
"httpMethod": "GET",
"url": "api/cms-kit-public/blog-posts/authors/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.CmsKit.Users.CmsUserDto",
"typeSimple": "Volo.CmsKit.Users.CmsUserDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.CmsKit.Public.Blogs.IBlogPostPublicAppService"

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

@ -40,8 +40,15 @@ public class BlogPostPublicController : CmsKitPublicControllerBase, IBlogPostPub
[HttpGet]
[Route("authors")]
public virtual Task<List<CmsUserDto>> GetAuthorsHasBlogPostsAsync()
public Task<PagedResultDto<CmsUserDto>> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input)
{
return BlogPostPublicAppService.GetAuthorsHasBlogPostsAsync();
return BlogPostPublicAppService.GetAuthorsHasBlogPostsAsync(input);
}
[HttpGet]
[Route("authors/{id}")]
public Task<CmsUserDto> GetAuthorHasBlogPostAsync(Guid id)
{
return BlogPostPublicAppService.GetAuthorHasBlogPostAsync(id);
}
}

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

@ -16,94 +16,133 @@
@inject IMarkdownToHtmlRenderer MarkdownRenderer
@{
string dummyImageSource = "https://dummyimage.com/1280x720/a3a3a3/fff.png?text=" + Model.BlogPost.Title;
var isScrollIndexEnabled = GlobalFeatureManager.Instance.IsEnabled<BlogPostScrollIndexFeature>();
}
@section styles{
<abp-abp-style-bundle>
<abp-style src="/Pages/Public/CmsKit/Blogs/blogPost.css" />
<abp-style type="typeof(HighlightJsStyleContributor)" />
</abp-abp-style-bundle>
@if (isScrollIndexEnabled)
{
<abp-abp-style-bundle>
<abp-style src="/Pages/Public/CmsKit/Blogs/bootstrap-toc.css"/>
</abp-abp-style-bundle>
}
<abp-abp-style-bundle>
<abp-style src="/Pages/Public/CmsKit/Blogs/blogPost.css"/>
<abp-style type="typeof(HighlightJsStyleContributor)"/>
</abp-abp-style-bundle>
}
@section scripts{
<abp-script-bundle>
<abp-script type="typeof(HighlightJsScriptContributor)" />
<abp-script src="/Pages/Public/CmsKit/highlightOnLoad.js" />
</abp-script-bundle>
}
@if (isScrollIndexEnabled)
{
<abp-script-bundle>
<abp-style src="/Pages/Public/CmsKit/Blogs/bootstrap-toc.js"/>
<abp-script src="/Pages/Public/CmsKit/Blogs/blogpost-scroll-index.js"/>
</abp-script-bundle>
}
@{
string dummyImageSource = "https://dummyimage.com/1280x720/a3a3a3/fff.png?text=" + Model.BlogPost.Title;
<abp-script-bundle>
<abp-script type="typeof(HighlightJsScriptContributor)"/>
<abp-script src="/Pages/Public/CmsKit/highlightOnLoad.js"/>
</abp-script-bundle>
}
<abp-card class="mb-4">
<img src="/api/cms-kit/media/@Model.BlogPost.CoverImageMediaId" class="card-img-top" onerror="this.src='@dummyImageSource'" />
<abp-card-body>
<abp-row>
<div class="col-lg-8 col-md-10 mx-auto pb-4">
<h1 class="mt-lg-4 mt-md-3">@Model.BlogPost.Title</h1>
<p class="mb-lg-5 mb-md-3">
<a href="/blogs/@Model.BlogSlug?authorId=@Model.BlogPost.Author.Id">
<span class="font-weight-bold">@@@Model.BlogPost.Author?.UserName</span>
</a>
<small style="opacity:.65;">@Model.BlogPost.CreationTime</small>
</p>
@if(!Model.BlogPost.Content.IsNullOrEmpty())
{
@Html.Raw(await MarkdownRenderer.RenderAsync(Model.BlogPost.Content))
}
<p class="mb-3">
@if (Model.BlogPost.LastModificationTime != null)
{
<small style="opacity:.65;">@L["LastModification"].Value : @Model.BlogPost.LastModificationTime</small>
}
</p>
<hr />
@if (GlobalFeatureManager.Instance.IsEnabled<TagsFeature>())
{
if (Model.TagsFeature?.IsEnabled == true)
{
@await Component.InvokeAsync(typeof(TagViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}
}
</div>
</abp-row>
<abp-row class="row">
<abp-column size-lg="_6" size-md="_12">
@if (GlobalFeatureManager.Instance.IsEnabled<ReactionsFeature>())
{
if (Model.ReactionsFeature?.IsEnabled == true)
{
@await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new
<div class="row">
<div @Html.Raw(isScrollIndexEnabled ? "class=\"col-md-10 col-sm-12\"" : "class=\"col-md-12\"")>
<abp-card class="mb-4">
<img src="/api/cms-kit/media/@Model.BlogPost.CoverImageMediaId" class="card-img-top" onerror="this.src='@dummyImageSource'"/>
<abp-card-body>
<abp-row>
<div class="col-lg-8 col-md-10 mx-auto pb-4">
<h1 class="mt-lg-4 mt-md-3">@Model.BlogPost.Title</h1>
<p class="mb-lg-5 mb-md-3">
<a href="/blogs/@Model.BlogSlug?authorId=@Model.BlogPost.Author.Id">
<span class="font-weight-bold">@@@Model.BlogPost.Author?.UserName</span>
</a>
<small style="opacity:.65;">@Model.BlogPost.CreationTime</small>
</p>
@if (!Model.BlogPost.Content.IsNullOrEmpty())
{
@Html.Raw(await MarkdownRenderer.RenderAsync(Model.BlogPost.Content))
}
<p class="mb-3">
@if (Model.BlogPost.LastModificationTime != null)
{
<small style="opacity:.65;">@L["LastModification"].Value : @Model.BlogPost.LastModificationTime</small>
}
</p>
<hr/>
@if (GlobalFeatureManager.Instance.IsEnabled<TagsFeature>())
{
if (Model.TagsFeature?.IsEnabled == true)
{
@await Component.InvokeAsync(typeof(TagViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}
}
</div>
</abp-row>
<abp-row class="row">
<abp-column size-lg="_6" size-md="_12">
@if (GlobalFeatureManager.Instance.IsEnabled<ReactionsFeature>())
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}
}
</abp-column>
<abp-column size-lg="_6" size-md="_12">
@if (GlobalFeatureManager.Instance.IsEnabled<RatingsFeature>())
{
if (Model.RatingsFeature?.IsEnabled == true)
{
@await Component.InvokeAsync(typeof(RatingViewComponent), new
if (Model.ReactionsFeature?.IsEnabled == true)
{
@await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}
}
</abp-column>
<abp-column size-lg="_6" size-md="_12">
@if (GlobalFeatureManager.Instance.IsEnabled<RatingsFeature>())
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}
}
</abp-column>
</abp-row>
</abp-card-body>
</abp-card>
if (Model.RatingsFeature?.IsEnabled == true)
{
@await Component.InvokeAsync(typeof(RatingViewComponent), new
{
entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType,
entityId = Model.BlogPost.Id.ToString()
})
}
}
</abp-column>
</abp-row>
</abp-card-body>
</abp-card>
</div>
@if (isScrollIndexEnabled)
{
<div class="col-md-2 d-sm-none d-md-block">
<div id="scroll-index" class="docs-inner-anchors mt-2">
<h5>@L["InThisDocument"]</h5>
<nav id="blog-post-sticky-index" class="navbar index-scroll pt-0">
</nav>
<div class="row">
<div class="col p-0 py-3">
<a href="#" class="scroll-top-btn">
<i class="fa fa-chevron-up"></i> @L["GoToTop"]
</a>
</div>
</div>
</div>
</div>
}
</div>
@if (GlobalFeatureManager.Instance.IsEnabled<CommentsFeature>())
{

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

@ -24,19 +24,21 @@
<abp-row id="blogs-filter-area">
<abp-column size="_4">
<div class="mb-3">
<label class="form-label" asp-for="@Model.Authors"></label>
<select id="AuthorSelect" class="form-control">
<option value="">@L["SelectAnAuthor"]</option>
@foreach (var author in Model.Authors)
{
if (author.Id == Model.AuthorId)
{
<option value="@author.Id" selected>@author.Name @author.Surname</option>
}
else
{
<option value="@author.Id">@author.Name @author.Surname</option>
}
<label class="form-label" asp-for="@Model.SelectedAuthor"></label>
<select id="AuthorSelect" asp-for="@Model.AuthorId"
class="auto-complete-select"
data-placeholder="@L["SelectAnAuthor"]"
data-allow-clear="true"
data-autocomplete-api-url="/api/cms-kit-public/blog-posts/authors"
data-autocomplete-display-property="userName"
data-autocomplete-value-property="id"
data-autocomplete-items-property="items"
data-autocomplete-filter-param-name="filter">
@if(Model.SelectedAuthor != null)
{
<option selected value="@Model.AuthorId" selected="selected">@Model.SelectedAuthor.UserName</option>
}
</select>
</div>
@ -76,4 +78,4 @@
<abp-column>
<abp-paginator model="Model.PagerModel"/>
</abp-column>
</abp-row>
</abp-row>

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

@ -20,16 +20,15 @@ public class IndexModel : CmsKitPublicPageModelBase
[BindProperty(SupportsGet = true)]
public int CurrentPage { get; set; } = 1;
[BindProperty(SupportsGet = true)]
public Guid? AuthorId { get; set; }
public PagedResultDto<BlogPostPublicDto> Blogs { get; private set; }
public PagerModel PagerModel => new PagerModel(Blogs.TotalCount, Blogs.Items.Count, CurrentPage, PageSize, Request.Path.ToString());
[BindProperty(SupportsGet = true)]
public List<CmsUserDto> Authors { get; set; }
public CmsUserDto SelectedAuthor { get; set; }
protected IBlogPostPublicAppService BlogPostPublicAppService { get; }
@ -48,7 +47,10 @@ public class IndexModel : CmsKitPublicPageModelBase
MaxResultCount = PageSize,
AuthorId = AuthorId
});
Authors = await BlogPostPublicAppService.GetAuthorsHasBlogPostsAsync();
if (AuthorId != null)
{
SelectedAuthor = await BlogPostPublicAppService.GetAuthorHasBlogPostAsync(AuthorId.Value);
}
}
}

17
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogPost.css

@ -20,4 +20,21 @@ span.area-title {
}
.popover {
min-width: 276px;
}
#scroll-index {
position: sticky;
top: 20px;
}
#scroll-index .scroll-top-btn.showup{
display: block;
}
#scroll-index .scroll-top-btn{
display: none;
font-size: .85em;
color: #aaa;
text-decoration: none;
padding-left: 18px;
}

46
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogpost-scroll-index.js

@ -0,0 +1,46 @@
$(function () {
var $myNav = $('#blog-post-sticky-index');
var $scrollToTopBtn = $('.scroll-top-btn');
window.Toc.helpers.createNavList = function () {
return $('<ul class="nav nav-pills flex-column"></ul>');
};
window.Toc.helpers.createChildNavList = function ($parent) {
var $childList = this.createNavList();
$parent.append($childList);
return $childList;
};
window.Toc.helpers.generateNavEl = function (anchor, text) {
var $a = $('<a class="nav-link"></a>');
$a.attr('href', '#' + anchor);
$a.text(text);
var $li = $('<li class="nav-item"></li>');
$li.append($a);
return $li;
};
Toc.init($myNav);
$('body').scrollspy({
target: $myNav,
});
$scrollToTopBtn.click(function () {
$('html, body').animate({scrollTop: 0}, 'fast');
});
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function () {
scrollFunction()
};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
$scrollToTopBtn.addClass('showup');
} else {
$scrollToTopBtn.removeClass('showup');
}
}
});

60
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.css

@ -0,0 +1,60 @@
/*!
* Bootstrap Table of Contents v<%= version %> (http://afeld.github.io/bootstrap-toc/)
* Copyright 2015 Aidan Feldman
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */
/* All levels of nav */
nav[data-toggle='toc'] .nav > li > a {
display: block;
padding: 4px 20px;
font-size: 13px;
font-weight: 500;
color: #767676;
}
nav[data-toggle='toc'] .nav > li > a:hover,
nav[data-toggle='toc'] .nav > li > a:focus {
padding-left: 19px;
color: #563d7c;
text-decoration: none;
background-color: transparent;
border-left: 1px solid #563d7c;
}
nav[data-toggle='toc'] .nav-link.active,
nav[data-toggle='toc'] .nav-link.active:hover,
nav[data-toggle='toc'] .nav-link.active:focus {
padding-left: 18px;
font-weight: bold;
color: #563d7c;
background-color: transparent;
border-left: 2px solid #563d7c;
}
/* Nav: second level (shown on .active) */
nav[data-toggle='toc'] .nav-link + ul {
display: none; /* Hide by default, but at >768px, show it */
padding-bottom: 10px;
}
nav[data-toggle='toc'] .nav .nav > li > a {
padding-top: 1px;
padding-bottom: 1px;
padding-left: 30px;
font-size: 12px;
font-weight: normal;
}
nav[data-toggle='toc'] .nav .nav > li > a:hover,
nav[data-toggle='toc'] .nav .nav > li > a:focus {
padding-left: 29px;
}
nav[data-toggle='toc'] .nav .nav > li > .active,
nav[data-toggle='toc'] .nav .nav > li > .active:hover,
nav[data-toggle='toc'] .nav .nav > li > .active:focus {
padding-left: 28px;
font-weight: 500;
}
nav[data-toggle='toc'] .nav-link.active + ul {
display: block;
}

168
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.js

@ -0,0 +1,168 @@
/*!
* Bootstrap Table of Contents v1.0.0 (http://afeld.github.io/bootstrap-toc/)
* Copyright 2015 Aidan Feldman
* Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
(function ($) {
'use strict';
window.Toc = {
helpers: {
// return all matching elements in the set, or their descendants
findOrFilter: function ($el, selector) {
// http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
// http://stackoverflow.com/a/12731439/358804
var $descendants = $el.find(selector);
return $el
.filter(selector)
.add($descendants)
.filter(':not([data-toc-skip])');
},
generateUniqueIdBase: function (el) {
var text = $(el).text();
var anchor = text
.trim()
.toLowerCase()
.replace(/[^A-Za-z0-9]+/g, '-');
return anchor || el.tagName.toLowerCase();
},
generateUniqueId: function (el) {
var anchorBase = this.generateUniqueIdBase(el);
for (var i = 0; ; i++) {
var anchor = anchorBase;
if (i > 0) {
// add suffix
anchor += '-' + i;
}
// check if ID already exists
if (!document.getElementById(anchor)) {
return anchor;
}
}
},
generateAnchor: function (el) {
if (el.id) {
return el.id;
} else {
var anchor = this.generateUniqueId(el);
el.id = anchor;
return anchor;
}
},
createNavList: function () {
return $('<ul class="nav navbar-nav"></ul>');
},
createChildNavList: function ($parent) {
var $childList = this.createNavList();
$parent.append($childList);
return $childList;
},
generateNavEl: function (anchor, text) {
var $a = $('<a class="nav-link"></a>');
$a.attr('href', '#' + anchor);
$a.text(text);
var $li = $('<li></li>');
$li.append($a);
return $li;
},
generateNavItem: function (headingEl) {
var anchor = this.generateAnchor(headingEl);
var $heading = $(headingEl);
var text = $heading.data('toc-text') || $heading.text();
return this.generateNavEl(anchor, text);
},
// Find the first heading level (`<h1>`, then `<h2>`, etc.) that has more than one element. Defaults to 1 (for `<h1>`).
getTopLevel: function ($scope) {
for (var i = 1; i <= 6; i++) {
var $headings = this.findOrFilter($scope, 'h' + i);
if ($headings.length > 1) {
return i;
}
}
return 1;
},
// returns the elements for the top level, and the next below it
getHeadings: function ($scope, topLevel) {
var topSelector = 'h' + topLevel;
var secondaryLevel = topLevel + 1;
var secondarySelector = 'h' + secondaryLevel;
return this.findOrFilter(
$scope,
topSelector + ',' + secondarySelector
);
},
getNavLevel: function (el) {
return parseInt(el.tagName.charAt(1), 10);
},
populateNav: function ($topContext, topLevel, $headings) {
var $context = $topContext;
var $prevNav;
var helpers = this;
$headings.each(function (i, el) {
var $newNav = helpers.generateNavItem(el);
var navLevel = helpers.getNavLevel(el);
// determine the proper $context
if (navLevel === topLevel) {
// use top level
$context = $topContext;
} else if ($prevNav && $context === $topContext) {
// create a new level of the tree and switch to it
$context = helpers.createChildNavList($prevNav);
} // else use the current $context
$context.append($newNav);
$prevNav = $newNav;
});
},
parseOps: function (arg) {
var opts;
if (arg.jquery) {
opts = {
$nav: arg,
};
} else {
opts = arg;
}
opts.$scope = opts.$scope || $(document.body);
return opts;
},
},
// accepts a jQuery object, or an options object
init: function (opts) {
opts = this.helpers.parseOps(opts);
// ensure that the data attribute is in place for styling
opts.$nav.attr('data-toggle', 'toc');
var $topContext = this.helpers.createChildNavList(opts.$nav);
var topLevel = this.helpers.getTopLevel(opts.$scope);
var $headings = this.helpers.getHeadings(opts.$scope, topLevel);
this.helpers.populateNav($topContext, topLevel, $headings);
},
};
$(function () {
$('nav[data-toggle="toc"]').each(function (i, el) {
var $nav = $(el);
Toc.init($nav);
});
});
})(jQuery);

22
modules/cms-kit/src/Volo.CmsKit.Public.Web/wwwroot/client-proxies/cms-kit-proxy.js

@ -112,6 +112,28 @@
})();
// controller volo.cmsKit.public.globalResources.globalResourcePublic
(function(){
abp.utils.createNamespace(window, 'volo.cmsKit.public.globalResources.globalResourcePublic');
volo.cmsKit.public.globalResources.globalResourcePublic.getGlobalScript = function(ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/cms-kit-public/global-resources/script',
type: 'GET'
}, ajaxParams));
};
volo.cmsKit.public.globalResources.globalResourcePublic.getGlobalStyle = function(ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/cms-kit-public/global-resources/style',
type: 'GET'
}, ajaxParams));
};
})();
// controller volo.cmsKit.public.comments.commentPublic
(function(){

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

@ -155,7 +155,7 @@ public abstract class BlogPostRepository_Test<TStartupModule> : CmsKitTestBase<T
[Fact]
public async Task GetAuthorsHasBlogPosts_ShouldWorkProperly()
{
var authors = await blogPostRepository.GetAuthorsHasBlogPosts();
var authors = await blogPostRepository.GetAuthorsHasBlogPostsAsync(0, 100, null, null);
authors.ShouldNotBeNull();
authors.ShouldNotBeEmpty();

2
npm/ng-packs/packages/core/src/lib/models/environment.ts

@ -10,8 +10,8 @@ export interface Environment {
oAuthConfig: AuthConfig;
production: boolean;
remoteEnv?: RemoteEnv;
[key:string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
}
export interface ApplicationInfo {
name: string;
baseUrl?: string;

Loading…
Cancel
Save