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

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>
`,
})

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

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(

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

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

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": [
{

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.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Blogs;
@ -11,11 +12,13 @@ public interface IBlogPostRepository : IBasicRepository<BlogPost, Guid>
Task<int> GetCountAsync(
string filter = null,
Guid? blogId = null,
Guid? authorId = null,
CancellationToken cancellationToken = default);
Task<List<BlogPost>> GetListAsync(
string filter = null,
Guid? blogId = null,
Guid? authorId = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string sorting = null,
@ -24,4 +27,6 @@ public interface IBlogPostRepository : IBasicRepository<BlogPost, Guid>
Task<bool> SlugExistsAsync(Guid blogId, string slug, CancellationToken cancellationToken = default);
Task<BlogPost> GetBySlugAsync(Guid blogId, string slug, CancellationToken cancellationToken = default);
}
Task<List<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(
string filter = null,
Guid? blogId = null,
Guid? authorId = null,
CancellationToken cancellationToken = default)
{
var queryable = (await GetDbSetAsync())
.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));
var count = await queryable.CountAsync(GetCancellationToken(cancellationToken));
@ -54,6 +56,7 @@ public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPo
public virtual async Task<List<BlogPost>> GetListAsync(
string filter = null,
Guid? blogId = null,
Guid? authorId = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string sorting = null,
@ -66,7 +69,8 @@ public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPo
var queryable = blogPostsDbSet
.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);
@ -95,4 +99,10 @@ public class EfCoreBlogPostRepository : EfCoreRepository<CmsKitDbContext, BlogPo
return await (await GetDbSetAsync()).AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug,
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(
string filter = null,
Guid? blogId = null,
Guid? authorId = null,
CancellationToken cancellationToken = default)
{
cancellationToken = GetCancellationToken(cancellationToken);
@ -49,12 +50,15 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
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>>(blogId.HasValue, x => x.BlogId == blogId)
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(authorId.HasValue, x => x.AuthorId == authorId)
.CountAsync(cancellationToken);
}
public virtual async Task<List<BlogPost>> GetListAsync(
string filter = null,
Guid? blogId = null,
Guid? authorId = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string sorting = null,
@ -68,7 +72,8 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
var queryable = blogPostQueryable
.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);
@ -99,4 +104,22 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
var queryable = await GetMongoQueryableAsync(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 Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Public.Blogs;
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<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.CmsKit.Blogs;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Public.Blogs;
@ -14,6 +15,7 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub
protected IBlogRepository BlogRepository { get; }
protected IBlogPostRepository BlogPostRepository { get; }
public BlogPostPublicAppService(
IBlogRepository blogRepository,
@ -32,14 +34,21 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub
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 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>(
await BlogPostRepository.GetCountAsync(blogId: blog.Id),
await BlogPostRepository.GetCountAsync(blogId: blog.Id, authorId: input.AuthorId),
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
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
@ -7,6 +8,7 @@ using Volo.Abp.Http.Modeling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.CmsKit.Public.Blogs;
using Volo.CmsKit.Users;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Blogs.ClientProxies;
@ -23,13 +25,18 @@ public partial class BlogPostPublicClientProxy : ClientProxyBase<IBlogPostPublic
{ 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
{
{ 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": {
"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": [
{

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

@ -1,11 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Content;
using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Public.Blogs;
@ -31,8 +33,15 @@ public class BlogPostPublicController : CmsKitPublicControllerBase, IBlogPostPub
[HttpGet]
[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);
}
}
[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>();
}
<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">
<img src="/api/cms-kit/media/@Model.BlogPost.CoverImageMediaId" class="card-img-top" onerror="this.src='@dummyImageSource'"/>
<abp-card-body>
@ -47,10 +48,11 @@
<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">
<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>
</p>
@if (!Model.BlogPost.Content.IsNullOrEmpty())
{
@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
@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";
}
<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">
@foreach (var blog in Model.Blogs.Items)
{
@ -21,16 +49,16 @@
<abp-card>
@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
{
<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">
<h5>@blog.Title</h5>
<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>
</p>
<p style="min-height: 60px;">@blog.ShortDescription</p>
@ -42,11 +70,10 @@
</abp-card-body>
</abp-card>
</abp-column>
}
</abp-row>
<abp-row>
<abp-column>
<abp-paginator model="Model.PagerModel" />
<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

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination;
using Volo.CmsKit.Public.Blogs;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs;
@ -19,10 +20,16 @@ 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; }
protected IBlogPostPublicAppService BlogPostPublicAppService { get; }
@ -35,10 +42,13 @@ public class IndexModel : CmsKitPublicPageModelBase
{
Blogs = await BlogPostPublicAppService.GetListAsync(
BlogSlug,
new PagedAndSortedResultRequestDto
new BlogPostGetListInput
{
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 {
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
(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.Domain.Entities;
using Volo.CmsKit.Public.Blogs;
using Volo.CmsKit.Users;
using Xunit;
namespace Volo.CmsKit.Blogs;
@ -17,16 +18,26 @@ public class BlogPostPublicAppService_Tests : CmsKitApplicationTestBase
private readonly CmsKitTestData cmsKitTestData;
private readonly ICmsUserRepository userRepository;
private readonly IBlogRepository blogRepository;
private readonly IBlogPostRepository blogPostRepository;
private readonly BlogPostManager blogPostManager;
public BlogPostPublicAppService_Tests()
{
blogPostAppService = GetRequiredService<IBlogPostPublicAppService>();
cmsKitTestData = GetRequiredService<CmsKitTestData>();
userRepository = GetRequiredService<ICmsUserRepository>();
blogRepository = GetRequiredService<IBlogRepository>();
blogPostManager = GetRequiredService<BlogPostManager>();
blogPostRepository = GetRequiredService<IBlogPostRepository>();
}
[Fact]
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.TotalCount.ShouldBe(2);
@ -62,4 +73,49 @@ public class BlogPostPublicAppService_Tests : CmsKitApplicationTestBase
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.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