Browse Source

Merge branch 'dev' into pr/11961

pull/12121/head
Musa Demir 5 years ago
parent
commit
fe5623eb4a
No known key found for this signature in database GPG Key ID: 117DF92322553DC8
  1. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  2. 7
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  3. 2
      docs/en/AspNet-Boilerplate-Migration-Guide.md
  4. 2
      docs/en/UI/Angular/Theming.md
  5. 3
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs
  6. 1
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs
  7. 15
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs
  8. 4
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs
  9. 11
      framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqConsts.cs
  10. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostGetListInput.cs
  11. 5
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs
  12. 20
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json
  13. 7
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs
  14. 12
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs
  15. 25
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs
  16. 9
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostGetListInput.cs
  17. 8
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs
  18. 15
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs
  19. 13
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs
  20. 27
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.Generated.cs
  21. 7
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.cs
  22. 58
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json
  23. 13
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs
  24. 8
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml
  25. 41
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml
  26. 14
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs
  27. 4
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/index.css
  28. 18
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/index.js
  29. 22
      modules/cms-kit/src/Volo.CmsKit.Public.Web/wwwroot/client-proxies/cms-kit-proxy.js
  30. 58
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostPublicAppService_Tests.cs
  31. 10
      modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs

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

@ -380,6 +380,7 @@
"PurchaseItems": "Purchase Items", "PurchaseItems": "Purchase Items",
"SuccessfullyUpdated": "Successfully updated", "SuccessfullyUpdated": "Successfully updated",
"SuccessfullyAdded": "Successfully added", "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!", "LicenseTypeNotCorrect": "The license type is not correct!",
"Trainings": "Trainings", "Trainings": "Trainings",
"ChoseTrainingPlaceholder": "Chose the training...", "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>", "ForMoreInformationClickHere": "For more information, click <a href='{0}'>here.</a>",
"IsGetOnboardingTraining": "Would you like to get onboarding & web application development training?", "IsGetOnboardingTraining": "Would you like to get onboarding & web application development training?",
"OnboardingWebApplicationDevelopmentTrainingMessage": "To schedule your training calendar, please contact {0} after creating the organization", "OnboardingWebApplicationDevelopmentTrainingMessage": "To schedule your training calendar, please contact {0} after creating the organization",
@ -503,6 +505,7 @@
"AdditionalNote": "Additional Note", "AdditionalNote": "Additional Note",
"OnboardingTrainingFaqTitle": "Do you have ABP onboarding training?", "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>.", "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. 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.

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

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

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)) if (receivedContext.Request.Cookies.ContainsKey(tenantKey))
{ {
receivedContext.TokenEndpointRequest.SetParameter(tenantKey, receivedContext.TokenEndpointRequest?.SetParameter(tenantKey, receivedContext.Request.Cookies[tenantKey]);
receivedContext.Request.Cookies[tenantKey]);
} }
} }
} }

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.StatusCode = (int)statusCodeFinder.GetStatusCode(httpContext, exception);
httpContext.Response.OnStarting(_clearCacheHeadersDelegate, httpContext.Response); httpContext.Response.OnStarting(_clearCacheHeadersDelegate, httpContext.Response);
httpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); httpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
httpContext.Response.Headers.Add("Content-Type", "application/json");
await httpContext.Response.WriteAsync( await httpContext.Response.WriteAsync(
jsonSerializer.Serialize( jsonSerializer.Serialize(

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 class AbpRabbitMqEventBusOptions
{ {
public const string DefaultExchangeType = RabbitMqConsts.ExchangeTypes.Direct;
public string ConnectionName { get; set; } public string ConnectionName { get; set; }
public string ClientName { get; set; } public string ClientName { get; set; }
public string ExchangeName { 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( Consumer = MessageConsumerFactory.Create(
new ExchangeDeclareConfiguration( new ExchangeDeclareConfiguration(
AbpRabbitMqEventBusOptions.ExchangeName, AbpRabbitMqEventBusOptions.ExchangeName,
type: "direct", type: AbpRabbitMqEventBusOptions.GetExchangeTypeOrDefault(),
durable: true durable: true
), ),
new QueueDeclareConfiguration( new QueueDeclareConfiguration(
@ -244,7 +244,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
{ {
channel.ExchangeDeclare( channel.ExchangeDeclare(
AbpRabbitMqEventBusOptions.ExchangeName, AbpRabbitMqEventBusOptions.ExchangeName,
"direct", AbpRabbitMqEventBusOptions.GetExchangeTypeOrDefault(),
durable: true 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 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";
}
} }

2
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostGetListInput.cs

@ -8,4 +8,6 @@ public class BlogPostGetListInput : PagedAndSortedResultRequestDto
public string Filter { get; set; } public string Filter { get; set; }
public Guid? BlogId { get; set; } public Guid? BlogId { get; set; }
public Guid? AuthorId { get; set; }
} }

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

@ -89,9 +89,10 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe
{ {
var blogs = (await BlogRepository.GetListAsync()).ToDictionary(x => x.Id); var blogs = (await BlogRepository.GetListAsync()).ToDictionary(x => x.Id);
var blogPosts = await BlogPostRepository.GetListAsync(input.Filter, input.BlogId, input.MaxResultCount, input.SkipCount, input.Sorting); var blogPosts = await BlogPostRepository.GetListAsync(input.Filter, input.BlogId, input.AuthorId,
input.MaxResultCount, input.SkipCount, input.Sorting);
var count = await BlogPostRepository.GetCountAsync(input.Filter); var count = await BlogPostRepository.GetCountAsync(input.Filter, input.BlogId, input.AuthorId);
var dtoList = blogPosts.Select(x => var dtoList = blogPosts.Select(x =>
{ {

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

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

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Blogs; namespace Volo.CmsKit.Blogs;
@ -11,11 +12,13 @@ public interface IBlogPostRepository : IBasicRepository<BlogPost, Guid>
Task<int> GetCountAsync( Task<int> GetCountAsync(
string filter = null, string filter = null,
Guid? blogId = null, Guid? blogId = null,
Guid? authorId = null,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
Task<List<BlogPost>> GetListAsync( Task<List<BlogPost>> GetListAsync(
string filter = null, string filter = null,
Guid? blogId = null, Guid? blogId = null,
Guid? authorId = null,
int maxResultCount = int.MaxValue, int maxResultCount = int.MaxValue,
int skipCount = 0, int skipCount = 0,
string sorting = null, string sorting = null,
@ -24,4 +27,6 @@ public interface IBlogPostRepository : IBasicRepository<BlogPost, Guid>
Task<bool> SlugExistsAsync(Guid blogId, string slug, CancellationToken cancellationToken = default); Task<bool> SlugExistsAsync(Guid blogId, string slug, CancellationToken cancellationToken = default);
Task<BlogPost> GetBySlugAsync(Guid blogId, string slug, CancellationToken cancellationToken = default); Task<BlogPost> GetBySlugAsync(Guid blogId, string slug, CancellationToken cancellationToken = default);
}
Task<List<CmsUser>> GetAuthorsHasBlogPosts(CancellationToken cancellationToken = default);
}

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

@ -41,10 +41,12 @@ public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPo
public virtual async Task<int> GetCountAsync( public virtual async Task<int> GetCountAsync(
string filter = null, string filter = null,
Guid? blogId = null, Guid? blogId = null,
Guid? authorId = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var queryable = (await GetDbSetAsync()) var queryable = (await GetDbSetAsync())
.WhereIf(blogId.HasValue, x => x.BlogId == blogId) .WhereIf(blogId.HasValue, x => x.BlogId == blogId)
.WhereIf(authorId.HasValue, x => x.AuthorId == authorId)
.WhereIf(!string.IsNullOrEmpty(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter)); .WhereIf(!string.IsNullOrEmpty(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter));
var count = await queryable.CountAsync(GetCancellationToken(cancellationToken)); var count = await queryable.CountAsync(GetCancellationToken(cancellationToken));
@ -54,6 +56,7 @@ public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPo
public virtual async Task<List<BlogPost>> GetListAsync( public virtual async Task<List<BlogPost>> GetListAsync(
string filter = null, string filter = null,
Guid? blogId = null, Guid? blogId = null,
Guid? authorId = null,
int maxResultCount = int.MaxValue, int maxResultCount = int.MaxValue,
int skipCount = 0, int skipCount = 0,
string sorting = null, string sorting = null,
@ -66,7 +69,8 @@ public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPo
var queryable = blogPostsDbSet var queryable = blogPostsDbSet
.WhereIf(blogId.HasValue, x => x.BlogId == blogId) .WhereIf(blogId.HasValue, x => x.BlogId == blogId)
.WhereIf(!string.IsNullOrWhiteSpace(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter)); .WhereIf(!string.IsNullOrWhiteSpace(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter))
.WhereIf(authorId.HasValue, x => x.AuthorId == authorId);
queryable = queryable.OrderBy(sorting.IsNullOrEmpty() ? $"{nameof(BlogPost.CreationTime)} desc" : sorting); queryable = queryable.OrderBy(sorting.IsNullOrEmpty() ? $"{nameof(BlogPost.CreationTime)} desc" : sorting);
@ -95,4 +99,10 @@ public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPo
return await (await GetDbSetAsync()).AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug, return await (await GetDbSetAsync()).AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug,
GetCancellationToken(cancellationToken)); GetCancellationToken(cancellationToken));
} }
public async Task<List<CmsUser>> GetAuthorsHasBlogPosts(CancellationToken cancellationToken = default)
{
return await (await GetDbContextAsync()).BlogPosts.Select(x => x.Author).Distinct()
.ToListAsync(GetCancellationToken(cancellationToken));
}
} }

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

@ -42,6 +42,7 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
public virtual async Task<int> GetCountAsync( public virtual async Task<int> GetCountAsync(
string filter = null, string filter = null,
Guid? blogId = null, Guid? blogId = null,
Guid? authorId = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
@ -49,12 +50,15 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetMongoQueryableAsync(cancellationToken))
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(!string.IsNullOrWhiteSpace(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter)) .WhereIf<BlogPost, IMongoQueryable<BlogPost>>(!string.IsNullOrWhiteSpace(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter))
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(blogId.HasValue, x => x.BlogId == blogId) .WhereIf<BlogPost, IMongoQueryable<BlogPost>>(blogId.HasValue, x => x.BlogId == blogId)
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(authorId.HasValue, x => x.AuthorId == authorId)
.CountAsync(cancellationToken); .CountAsync(cancellationToken);
} }
public virtual async Task<List<BlogPost>> GetListAsync( public virtual async Task<List<BlogPost>> GetListAsync(
string filter = null, string filter = null,
Guid? blogId = null, Guid? blogId = null,
Guid? authorId = null,
int maxResultCount = int.MaxValue, int maxResultCount = int.MaxValue,
int skipCount = 0, int skipCount = 0,
string sorting = null, string sorting = null,
@ -68,7 +72,8 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
var queryable = blogPostQueryable var queryable = blogPostQueryable
.WhereIf(blogId.HasValue, x => x.BlogId == blogId) .WhereIf(blogId.HasValue, x => x.BlogId == blogId)
.WhereIf(!string.IsNullOrWhiteSpace(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter)); .WhereIf(!string.IsNullOrWhiteSpace(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter))
.WhereIf(authorId.HasValue, x => x.AuthorId == authorId);
queryable = queryable.OrderBy(sorting.IsNullOrEmpty() ? $"{nameof(BlogPost.CreationTime)} desc" : sorting); queryable = queryable.OrderBy(sorting.IsNullOrEmpty() ? $"{nameof(BlogPost.CreationTime)} desc" : sorting);
@ -99,4 +104,22 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
var queryable = await GetMongoQueryableAsync(cancellationToken); var queryable = await GetMongoQueryableAsync(cancellationToken);
return await queryable.AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug, cancellationToken); return await queryable.AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug, cancellationToken);
} }
public async Task<List<CmsUser>> GetAuthorsHasBlogPosts(CancellationToken cancellationToken = default)
{
var blogPostQueryable = (await GetQueryableAsync());
var usersQueryable = (await GetDbContextAsync()).Collection<CmsUser>().AsQueryable();
var queryable = blogPostQueryable
.Join(
usersQueryable,
o => o.AuthorId,
i => i.Id,
(blogPost, user) => new { blogPost, user })
.Select(s => s.user)
.Distinct();
return await AsyncExecuter.ToListAsync(queryable, GetCancellationToken(cancellationToken));
}
} }

9
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostGetListInput.cs

@ -0,0 +1,9 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Volo.CmsKit.Public.Blogs;
public class BlogPostGetListInput : PagedAndSortedResultRequestDto
{
public Guid? AuthorId { get; set; }
}

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

@ -1,13 +1,17 @@
using JetBrains.Annotations; using System.Collections.Generic;
using JetBrains.Annotations;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Public.Blogs; namespace Volo.CmsKit.Public.Blogs;
public interface IBlogPostPublicAppService : IApplicationService public interface IBlogPostPublicAppService : IApplicationService
{ {
Task<PagedResultDto<BlogPostPublicDto>> GetListAsync([NotNull] string blogSlug, PagedAndSortedResultRequestDto input); Task<PagedResultDto<BlogPostPublicDto>> GetListAsync([NotNull] string blogSlug, BlogPostGetListInput input);
Task<BlogPostPublicDto> GetAsync([NotNull] string blogSlug, [NotNull] string blogPostSlug); Task<BlogPostPublicDto> GetAsync([NotNull] string blogSlug, [NotNull] string blogPostSlug);
Task<List<CmsUserDto>> GetAuthorsHasBlogPostsAsync();
} }

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

@ -5,6 +5,7 @@ using Volo.Abp.Application.Dtos;
using Volo.Abp.GlobalFeatures; using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Public.Blogs; namespace Volo.CmsKit.Public.Blogs;
@ -14,6 +15,7 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub
protected IBlogRepository BlogRepository { get; } protected IBlogRepository BlogRepository { get; }
protected IBlogPostRepository BlogPostRepository { get; } protected IBlogPostRepository BlogPostRepository { get; }
public BlogPostPublicAppService( public BlogPostPublicAppService(
IBlogRepository blogRepository, IBlogRepository blogRepository,
@ -32,14 +34,21 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub
return ObjectMapper.Map<BlogPost, BlogPostPublicDto>(blogPost); return ObjectMapper.Map<BlogPost, BlogPostPublicDto>(blogPost);
} }
public virtual async Task<PagedResultDto<BlogPostPublicDto>> GetListAsync([NotNull] string blogSlug, PagedAndSortedResultRequestDto input) public virtual async Task<PagedResultDto<BlogPostPublicDto>> GetListAsync([NotNull] string blogSlug, BlogPostGetListInput input)
{ {
var blog = await BlogRepository.GetBySlugAsync(blogSlug); var blog = await BlogRepository.GetBySlugAsync(blogSlug);
var blogPosts = await BlogPostRepository.GetListAsync(null, blog.Id, input.MaxResultCount, input.SkipCount, input.Sorting); var blogPosts = await BlogPostRepository.GetListAsync(null, blog.Id, input.AuthorId, input.MaxResultCount,
input.SkipCount, input.Sorting);
return new PagedResultDto<BlogPostPublicDto>( return new PagedResultDto<BlogPostPublicDto>(
await BlogPostRepository.GetCountAsync(blogId: blog.Id), await BlogPostRepository.GetCountAsync(blogId: blog.Id, authorId: input.AuthorId),
ObjectMapper.Map<List<BlogPost>, List<BlogPostPublicDto>>(blogPosts)); ObjectMapper.Map<List<BlogPost>, List<BlogPostPublicDto>>(blogPosts));
} }
public virtual async Task<List<CmsUserDto>> GetAuthorsHasBlogPostsAsync()
{
var authors = await BlogPostRepository.GetAuthorsHasBlogPosts();
return ObjectMapper.Map<List<CmsUser>, List<CmsUserDto>>(authors);
}
} }

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

@ -1,5 +1,6 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp // This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client; using Volo.Abp.Http.Client;
@ -7,6 +8,7 @@ using Volo.Abp.Http.Modeling;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying; using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Public.Blogs; using Volo.CmsKit.Public.Blogs;
using Volo.CmsKit.Users;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Blogs.ClientProxies; namespace Volo.CmsKit.Public.Blogs.ClientProxies;
@ -23,13 +25,18 @@ public partial class BlogPostPublicClientProxy : ClientProxyBase<IBlogPostPublic
{ typeof(string), blogPostSlug } { typeof(string), blogPostSlug }
}); });
} }
public virtual async Task<PagedResultDto<BlogPostPublicDto>> GetListAsync(string blogSlug, PagedAndSortedResultRequestDto input) public virtual async Task<PagedResultDto<BlogPostPublicDto>> GetListAsync(string blogSlug, BlogPostGetListInput input)
{ {
return await RequestAsync<PagedResultDto<BlogPostPublicDto>>(nameof(GetListAsync), new ClientProxyRequestTypeValue return await RequestAsync<PagedResultDto<BlogPostPublicDto>>(nameof(GetListAsync), new ClientProxyRequestTypeValue
{ {
{ typeof(string), blogSlug }, { typeof(string), blogSlug },
{ typeof(PagedAndSortedResultRequestDto), input } { typeof(BlogPostGetListInput), input }
}); });
} }
public virtual async Task<List<CmsUserDto>> GetAuthorsHasBlogPostsAsync()
{
return await RequestAsync<List<CmsUserDto>>(nameof(GetAuthorsHasBlogPostsAsync));
}
} }

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

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

@ -7,6 +7,8 @@
"Volo.CmsKit.Public.Tags.TagPublicController": { "Volo.CmsKit.Public.Tags.TagPublicController": {
"controllerName": "TagPublic", "controllerName": "TagPublic",
"controllerGroupName": "TagPublic", "controllerGroupName": "TagPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Tags.TagPublicController", "type": "Volo.CmsKit.Public.Tags.TagPublicController",
"interfaces": [ "interfaces": [
{ {
@ -76,6 +78,8 @@
"Volo.CmsKit.Public.Reactions.ReactionPublicController": { "Volo.CmsKit.Public.Reactions.ReactionPublicController": {
"controllerName": "ReactionPublic", "controllerName": "ReactionPublic",
"controllerGroupName": "ReactionPublic", "controllerGroupName": "ReactionPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Reactions.ReactionPublicController", "type": "Volo.CmsKit.Public.Reactions.ReactionPublicController",
"interfaces": [ "interfaces": [
{ {
@ -299,6 +303,8 @@
"Volo.CmsKit.Public.Ratings.RatingPublicController": { "Volo.CmsKit.Public.Ratings.RatingPublicController": {
"controllerName": "RatingPublic", "controllerName": "RatingPublic",
"controllerGroupName": "RatingPublic", "controllerGroupName": "RatingPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Ratings.RatingPublicController", "type": "Volo.CmsKit.Public.Ratings.RatingPublicController",
"interfaces": [ "interfaces": [
{ {
@ -502,6 +508,8 @@
"Volo.CmsKit.Public.Pages.PagesPublicController": { "Volo.CmsKit.Public.Pages.PagesPublicController": {
"controllerName": "PagesPublic", "controllerName": "PagesPublic",
"controllerGroupName": "PagesPublic", "controllerGroupName": "PagesPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Pages.PagesPublicController", "type": "Volo.CmsKit.Public.Pages.PagesPublicController",
"interfaces": [ "interfaces": [
{ {
@ -551,6 +559,8 @@
"Volo.CmsKit.Public.Menus.MenuItemPublicController": { "Volo.CmsKit.Public.Menus.MenuItemPublicController": {
"controllerName": "MenuItemPublic", "controllerName": "MenuItemPublic",
"controllerGroupName": "MenuItemPublic", "controllerGroupName": "MenuItemPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Menus.MenuItemPublicController", "type": "Volo.CmsKit.Public.Menus.MenuItemPublicController",
"interfaces": [ "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": { "Volo.CmsKit.Public.Comments.CommentPublicController": {
"controllerName": "CommentPublic", "controllerName": "CommentPublic",
"controllerGroupName": "CommentPublic", "controllerGroupName": "CommentPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Comments.CommentPublicController", "type": "Volo.CmsKit.Public.Comments.CommentPublicController",
"interfaces": [ "interfaces": [
{ {
@ -818,6 +874,8 @@
"Volo.CmsKit.Public.Blogs.BlogPostPublicController": { "Volo.CmsKit.Public.Blogs.BlogPostPublicController": {
"controllerName": "BlogPostPublic", "controllerName": "BlogPostPublic",
"controllerGroupName": "BlogPostPublic", "controllerGroupName": "BlogPostPublic",
"isRemoteService": true,
"apiVersion": null,
"type": "Volo.CmsKit.Public.Blogs.BlogPostPublicController", "type": "Volo.CmsKit.Public.Blogs.BlogPostPublicController",
"interfaces": [ "interfaces": [
{ {

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

@ -1,11 +1,13 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Content; using Volo.Abp.Content;
using Volo.Abp.GlobalFeatures; using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Public.Blogs; namespace Volo.CmsKit.Public.Blogs;
@ -31,8 +33,15 @@ public class BlogPostPublicController : CmsKitPublicControllerBase, IBlogPostPub
[HttpGet] [HttpGet]
[Route("{blogSlug}")] [Route("{blogSlug}")]
public virtual Task<PagedResultDto<BlogPostPublicDto>> GetListAsync(string blogSlug, PagedAndSortedResultRequestDto input) public virtual Task<PagedResultDto<BlogPostPublicDto>> GetListAsync(string blogSlug, BlogPostGetListInput input)
{ {
return BlogPostPublicAppService.GetListAsync(blogSlug, input); return BlogPostPublicAppService.GetListAsync(blogSlug, input);
} }
}
[HttpGet]
[Route("authors")]
public virtual Task<List<CmsUserDto>> GetAuthorsHasBlogPostsAsync()
{
return BlogPostPublicAppService.GetAuthorsHasBlogPostsAsync();
}
}

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

@ -38,8 +38,9 @@
var isScrollIndexEnabled = GlobalFeatureManager.Instance.IsEnabled<BlogPostScrollIndexFeature>(); var isScrollIndexEnabled = GlobalFeatureManager.Instance.IsEnabled<BlogPostScrollIndexFeature>();
} }
<div class="row"> <div class="row">
<div @Html.Raw(isScrollIndexEnabled?"class=\"col-md-10 col-sm-12\"":"class=\"col-md-12\"")> <div @Html.Raw(isScrollIndexEnabled ? "class=\"col-md-10 col-sm-12\"" : "class=\"col-md-12\"")>
<abp-card class="mb-4"> <abp-card class="mb-4">
<img src="/api/cms-kit/media/@Model.BlogPost.CoverImageMediaId" class="card-img-top" onerror="this.src='@dummyImageSource'"/> <img src="/api/cms-kit/media/@Model.BlogPost.CoverImageMediaId" class="card-img-top" onerror="this.src='@dummyImageSource'"/>
<abp-card-body> <abp-card-body>
@ -47,10 +48,11 @@
<div class="col-lg-8 col-md-10 mx-auto pb-4"> <div class="col-lg-8 col-md-10 mx-auto pb-4">
<h1 class="mt-lg-4 mt-md-3">@Model.BlogPost.Title</h1> <h1 class="mt-lg-4 mt-md-3">@Model.BlogPost.Title</h1>
<p class="mb-lg-5 mb-md-3"> <p class="mb-lg-5 mb-md-3">
<span class="font-weight-bold">@@@Model.BlogPost.Author?.UserName</span> <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> <small style="opacity:.65;">@Model.BlogPost.CreationTime</small>
</p> </p>
@if (!Model.BlogPost.Content.IsNullOrEmpty()) @if (!Model.BlogPost.Content.IsNullOrEmpty())
{ {
@Html.Raw(await MarkdownRenderer.RenderAsync(Model.BlogPost.Content)) @Html.Raw(await MarkdownRenderer.RenderAsync(Model.BlogPost.Content))

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

@ -8,12 +8,40 @@
@model IndexModel @model IndexModel
@section styles{ @section styles{
<abp-style src="/Pages/Public/CmsKit/Blogs/index.css" /> <abp-style src="/Pages/Public/CmsKit/Blogs/index.css"/>
} }
@section scripts {
<abp-script-bundle>
<abp-script src="/Pages/Public/CmsKit/Blogs/index.js"/>
</abp-script-bundle>
}
@{ @{
const string dummyImageSource = "https://dummyimage.com/320x180/a3a3a3/fff.png"; const string dummyImageSource = "https://dummyimage.com/320x180/a3a3a3/fff.png";
} }
<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-select">
<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>
}
}
</select>
</div>
</abp-column>
</abp-row>
<abp-row id="blogs-container"> <abp-row id="blogs-container">
@foreach (var blog in Model.Blogs.Items) @foreach (var blog in Model.Blogs.Items)
{ {
@ -21,16 +49,16 @@
<abp-card> <abp-card>
@if (blog.CoverImageMediaId != null) @if (blog.CoverImageMediaId != null)
{ {
<img src="/api/cms-kit/media/@blog.CoverImageMediaId" class="card-img-top" onerror="this.src='@dummyImageSource'" /> <img src="/api/cms-kit/media/@blog.CoverImageMediaId" class="card-img-top" onerror="this.src='@dummyImageSource'"/>
} }
else else
{ {
<img src="@(dummyImageSource)?text=@blog.Title" class="card-img-top" /> <img src="@(dummyImageSource)?text=@blog.Title" class="card-img-top"/>
} }
<abp-card-body class="p-4"> <abp-card-body class="p-4">
<h5>@blog.Title</h5> <h5>@blog.Title</h5>
<p class="mb-2"> <p class="mb-2">
<span class="font-weight-bold">@@@blog.Author?.UserName</span> <span class="font-weight-bold author-name-span" data-author-id="@blog.Author.Id">@@@blog.Author?.UserName</span>
<small style="opacity:.65;">@blog.CreationTime</small> <small style="opacity:.65;">@blog.CreationTime</small>
</p> </p>
<p style="min-height: 60px;">@blog.ShortDescription</p> <p style="min-height: 60px;">@blog.ShortDescription</p>
@ -42,11 +70,10 @@
</abp-card-body> </abp-card-body>
</abp-card> </abp-card>
</abp-column> </abp-column>
} }
</abp-row> </abp-row>
<abp-row> <abp-row>
<abp-column> <abp-column>
<abp-paginator model="Model.PagerModel" /> <abp-paginator model="Model.PagerModel"/>
</abp-column> </abp-column>
</abp-row> </abp-row>

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

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination;
using Volo.CmsKit.Public.Blogs; using Volo.CmsKit.Public.Blogs;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs; namespace Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs;
@ -19,10 +20,16 @@ public class IndexModel : CmsKitPublicPageModelBase
[BindProperty(SupportsGet = true)] [BindProperty(SupportsGet = true)]
public int CurrentPage { get; set; } = 1; public int CurrentPage { get; set; } = 1;
[BindProperty(SupportsGet = true)]
public Guid? AuthorId { get; set; }
public PagedResultDto<BlogPostPublicDto> Blogs { get; private set; } public PagedResultDto<BlogPostPublicDto> Blogs { get; private set; }
public PagerModel PagerModel => new PagerModel(Blogs.TotalCount, Blogs.Items.Count, CurrentPage, PageSize, Request.Path.ToString()); public PagerModel PagerModel => new PagerModel(Blogs.TotalCount, Blogs.Items.Count, CurrentPage, PageSize, Request.Path.ToString());
[BindProperty(SupportsGet = true)]
public List<CmsUserDto> Authors { get; set; }
protected IBlogPostPublicAppService BlogPostPublicAppService { get; } protected IBlogPostPublicAppService BlogPostPublicAppService { get; }
@ -35,10 +42,13 @@ public class IndexModel : CmsKitPublicPageModelBase
{ {
Blogs = await BlogPostPublicAppService.GetListAsync( Blogs = await BlogPostPublicAppService.GetListAsync(
BlogSlug, BlogSlug,
new PagedAndSortedResultRequestDto new BlogPostGetListInput
{ {
SkipCount = PageSize * (CurrentPage - 1), SkipCount = PageSize * (CurrentPage - 1),
MaxResultCount = PageSize MaxResultCount = PageSize,
AuthorId = AuthorId
}); });
Authors = await BlogPostPublicAppService.GetAuthorsHasBlogPostsAsync();
} }
} }

4
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/index.css

@ -3,4 +3,8 @@
.popover { .popover {
min-width: 276px; min-width: 276px;
}
.author-name-span{
cursor: pointer;
} }

18
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/index.js

@ -0,0 +1,18 @@
$(function () {
var $selectAuthor = $('#AuthorSelect');
var $authorNameSpan = $('.author-name-span');
$selectAuthor.on('change', function () {
var authorId = $selectAuthor.val();
reloadPageWithQueryString({'authorId': authorId});
});
$authorNameSpan.click(function () {
var authorId = $(this).data('author-id');
reloadPageWithQueryString({'authorId': authorId});
});
function reloadPageWithQueryString(param) {
window.location.href = window.location.pathname + "?" + $.param(param);
}
});

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 // controller volo.cmsKit.public.comments.commentPublic
(function(){ (function(){

58
modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostPublicAppService_Tests.cs

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.CmsKit.Public.Blogs; using Volo.CmsKit.Public.Blogs;
using Volo.CmsKit.Users;
using Xunit; using Xunit;
namespace Volo.CmsKit.Blogs; namespace Volo.CmsKit.Blogs;
@ -17,16 +18,26 @@ public class BlogPostPublicAppService_Tests : CmsKitApplicationTestBase
private readonly CmsKitTestData cmsKitTestData; private readonly CmsKitTestData cmsKitTestData;
private readonly ICmsUserRepository userRepository;
private readonly IBlogRepository blogRepository;
private readonly IBlogPostRepository blogPostRepository;
private readonly BlogPostManager blogPostManager;
public BlogPostPublicAppService_Tests() public BlogPostPublicAppService_Tests()
{ {
blogPostAppService = GetRequiredService<IBlogPostPublicAppService>(); blogPostAppService = GetRequiredService<IBlogPostPublicAppService>();
cmsKitTestData = GetRequiredService<CmsKitTestData>(); cmsKitTestData = GetRequiredService<CmsKitTestData>();
userRepository = GetRequiredService<ICmsUserRepository>();
blogRepository = GetRequiredService<IBlogRepository>();
blogPostManager = GetRequiredService<BlogPostManager>();
blogPostRepository = GetRequiredService<IBlogPostRepository>();
} }
[Fact] [Fact]
public async Task GetListAsync_ShouldWorkProperly_WithExistingBlog() public async Task GetListAsync_ShouldWorkProperly_WithExistingBlog()
{ {
var blogPosts = await blogPostAppService.GetListAsync(cmsKitTestData.BlogSlug, new PagedAndSortedResultRequestDto { MaxResultCount = 2 }); var blogPosts = await blogPostAppService.GetListAsync(cmsKitTestData.BlogSlug, new BlogPostGetListInput { MaxResultCount = 2 });
blogPosts.ShouldNotBeNull(); blogPosts.ShouldNotBeNull();
blogPosts.TotalCount.ShouldBe(2); blogPosts.TotalCount.ShouldBe(2);
@ -62,4 +73,49 @@ public class BlogPostPublicAppService_Tests : CmsKitApplicationTestBase
exception.EntityType.ShouldBe(typeof(Blog)); exception.EntityType.ShouldBe(typeof(Blog));
} }
[Fact]
public async Task GetListAsync_ShouldFilterByUser()
{
var user2 = await userRepository.GetAsync(cmsKitTestData.User2Id);
var blog = await blogRepository.GetAsync(cmsKitTestData.Blog_Id);
var blogPost = await blogPostManager.CreateAsync(
user2,
blog,
cmsKitTestData.BlogPost_1_Title + "by user2",
cmsKitTestData.BlogPost_1_Slug + "by user2",
"Short desc 1",
"Blog Post 1 Content"
);
await blogPostRepository.InsertAsync(blogPost);
//should get all not filtered by user
var blogPosts = await blogPostAppService.GetListAsync(cmsKitTestData.BlogSlug,
new BlogPostGetListInput {});
blogPosts.ShouldNotBeNull();
blogPosts.TotalCount.ShouldBe(3);
blogPosts.Items.ShouldNotBeEmpty();
blogPosts.Items.Count.ShouldBe(3);
//should get only one filtered by user
blogPosts = await blogPostAppService.GetListAsync(cmsKitTestData.BlogSlug,
new BlogPostGetListInput {AuthorId = user2.Id});
blogPosts.ShouldNotBeNull();
blogPosts.TotalCount.ShouldBe(1);
blogPosts.Items.ShouldNotBeEmpty();
blogPosts.Items.Count.ShouldBe(1);
//should get filtered by user1
blogPosts = await blogPostAppService.GetListAsync(cmsKitTestData.BlogSlug,
new BlogPostGetListInput {AuthorId = cmsKitTestData.User1Id});
blogPosts.ShouldNotBeNull();
blogPosts.TotalCount.ShouldBe(2);
blogPosts.Items.ShouldNotBeEmpty();
blogPosts.Items.Count.ShouldBe(2);
}
} }

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

@ -145,4 +145,14 @@ public abstract class BlogPostRepository_Test<TStartupModule> : CmsKitTestBase<T
result.ShouldNotBeEmpty(); result.ShouldNotBeEmpty();
result.Count.ShouldBe(2); result.Count.ShouldBe(2);
} }
[Fact]
public async Task GetAuthorsHasBlogPosts_ShouldWorkProperly()
{
var authors = await blogPostRepository.GetAuthorsHasBlogPosts();
authors.ShouldNotBeNull();
authors.ShouldNotBeEmpty();
authors.ShouldContain(x => x.Id == testData.User1Id);
}
} }

Loading…
Cancel
Save