Browse Source

Merge branch 'dev' of https://github.com/abpframework/abp into refactor/nav-items

pull/4404/head
mehmet-erim 6 years ago
parent
commit
354f742d60
  1. 2
      docs/en/Blob-Storing.md
  2. 2
      docs/en/Repositories.md
  3. 133
      docs/zh-Hans/Repositories.md
  4. 3
      docs/zh-Hans/SignalR-Integration.md
  5. 2
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/DefaultContainer.cs
  6. 15
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AbpDistributedEntityEventOptions.cs
  7. 12
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorList.cs
  8. 78
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorListExtensions.cs
  9. 6
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityToEtoMapper.cs
  10. 3
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionary.cs
  11. 2
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionaryItem.cs
  12. 9
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/IAutoEntityDistributedEventSelectorList.cs
  13. 74
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs
  14. 2
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/AbpDistributedEventBusOptions.cs
  15. 5
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs
  16. 4
      modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs
  17. 22
      modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/GetAllInput.cs
  18. 12
      modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json
  19. 36
      modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs
  20. 219
      modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml
  21. 3
      modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs
  22. 3
      modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.css
  23. 71
      modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js
  24. 1
      modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.min.css
  25. 6
      modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.scss
  26. 8
      modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj
  27. 6
      modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json
  28. 63
      modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json.defaults
  29. 4
      modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs
  30. 23
      modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentRepository.cs
  31. 103
      modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Documents/EFCoreDocumentRepository.cs
  32. 124
      modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Documents/MongoDocumentRepository.cs
  33. 4
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs
  34. 9
      modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs
  35. 15
      modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs
  36. 4
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs
  37. 4
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs
  38. 7
      npm/ng-packs/packages/core/src/lib/services/list.service.ts
  39. 13
      npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts
  40. 1
      samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs
  41. 6
      samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs

2
docs/en/Blob-Storing.md

@ -169,7 +169,7 @@ public class ProfileAppService : ApplicationService
If you don't use the generic argument and directly inject the `IBlobContainer` (as explained before), you get the default container. Another way of injecting the default container is using `IBlobContainer<DefaultContainer>`, which returns exactly the same container.
The name of the default container is `Default`.
The name of the default container is `default`.
### Named Containers

2
docs/en/Repositories.md

@ -126,7 +126,7 @@ You can directly access the data access provider (`DbContext` in this case) to p
`IRepository` inherits from `IQueryable`, that means you can **directly use LINQ extension methods** on it, as shown in the example of the "*Generic Repositories*" section above.
**Example: Using the `Where(...)` &and the `ToList()` extension methods**
**Example: Using the `Where(...)` and the `ToList()` extension methods**
````csharp
var people = _personRepository

133
docs/zh-Hans/Repositories.md

@ -38,6 +38,8 @@ public class PersonAppService : ApplicationService
}
````
> 参阅 "*IQueryable & 异步操作*" 部分了解如何使用 **异步扩展方法**, 如 `ToListAsync()` (建议始终使用异步) 而不是 `ToList()`.
在这个例子中;
* `PersonAppService` 在它的构造函数中注入了 `IRepository<Person, Guid>` .
@ -119,4 +121,133 @@ public class PersonRepository : EfCoreRepository<MyDbContext, Person, Guid>, IPe
}
````
你可以直接使用数据库访问提供程序 (本例中是 `DbContext` ) 来执行操作. 有关基于EF Core的自定义仓储的更多信息, 请参阅[EF Core 集成文档](Entity-Framework-Core.md).
你可以直接使用数据库访问提供程序 (本例中是 `DbContext` ) 来执行操作.
> 请参阅[EF Core](Entity-Framework-Core.md)或[MongoDb](MongoDB.md)了解如何自定义仓储.
## IQueryable & 异步操作
`IRepository` 继承自 `IQueryable`,这意味着你可以**直接使用LINQ扩展方法**. 如上面的*泛型仓储*示例.
**示例: 使用 `Where(...)` 和 `ToList()` 扩展方法**
````csharp
var people = _personRepository
.Where(p => p.Name.Contains(nameFilter))
.ToList();
````
`.ToList`, `Count()`... 是在 `System.Linq` 命名空间下定义的扩展方法. ([参阅所有方法](https://docs.microsoft.com/en-us/dotnet/api/system.linq.queryable)).
你通常想要使用 `.ToListAsync()`, `.CountAsync()`.... 来编写**真正的异步代码**.
但在你使用标准的[应用程序启动模板](Startup-Templates/Application.md)时会发现无法在应用层或领域层使用这些异步扩展方法,因为:
* 这里异步方法**不是标准LINQ方法**,它们定义在[Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore)Nuget包中.
* 标准模板应用层与领域层**不引用**EF Core 包以实现数据库提供程序独立.
根据你的需求和开发模式,你可以根据以下选项使用异步方法.s
> 强烈建议使用异步方法! 在执行数据库查询时不要使用同步LINQ方法,以便能够开发可伸缩的应用程序.
### 选项-1: 引用EF Core
最简单的方法是在你想要使用异步方法的项目直接引用EF Core包.
> 添加[Volo.Abp.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore)NuGet包到你的项目间接引用EF Core包. 这可以确保你的应用程序其余部分兼容正确版本的EF Core.
当你添加NuGet包后,你可以使用全功能的EF Core扩展方法.
**示例: 直接使用 `ToListAsync()`**
````csharp
var people = _personRepository
.Where(p => p.Name.Contains(nameFilter))
.ToListAsync();
````
此方法建议;
* 如果你正在开发一个应用程序并且**不打算在将来** 更新FE Core,或者如果以后需要更改,你可以**容忍**它. 如果你正在开发最终的应用程序,这是合理的.
#### MongoDB
如果使用的是MongoDB,则需要将[Volo.Abp.MongoDB] NuGet包添加到项目中. 但在这种情况下你也不能直接使用异步LINQ扩展(例如`ToListAsync`),因为MongoDB不提供 `IQueryable<T>`的异步扩展方法,而是提供 `IMongoQueryable<T>`. 你需要先将查询强制转换为 `IMongoQueryable<T>` 才能使用异步扩展方法.
**示例: 转换Cast `IQueryable<T>` 为 `IMongoQueryable<T>` 并且使用 `ToListAsync()`**
````csharp
var people = ((IMongoQueryable<Person>)_personRepository
.Where(p => p.Name.Contains(nameFilter)))
.ToListAsync();
````
### 选项-2: 自定义仓储方法
你始终可以创建自定义仓储方法并使用特定数据库提供程序的API,比如这里的异步扩展方法. 有关自定义存储库的更多信息,请参阅[EF Core](Entity-Framework-Core.md)或[MongoDb](MongoDB.md)文档.
此方法建议;
* 如果你想**完全隔离**你的领域和应用层和数据库提供程序.
* 如果你开发可**重用的[应用模块](Modules/Index.md)**,并且不想强制使用特定的数据库提供程序,这应该作为一种[最佳实践](Best-Practices/Index.md).
### 选项-3: IAsyncQueryableExecuter
> 注意,此功能在ABP框架3.0以之后的版本可用,虽然它也可以用于较早的版本,但它提供的方法非常有限.
`IAsyncQueryableExecuter` 是一个用于异步执行 `IQueryable<T>` 对象的服务,**不依赖于实际的数据库提供程序**.
**示例: 注入并使用 `IAsyncQueryableExecuter.ToListAsync()` 方法**
````csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
namespace AbpDemo
{
public class ProductAppService : ApplicationService, IProductAppService
{
private readonly IRepository<Product, Guid> _productRepository;
private readonly IAsyncQueryableExecuter _asyncExecuter;
public ProductAppService(
IRepository<Product, Guid> productRepository,
IAsyncQueryableExecuter asyncExecuter)
{
_productRepository = productRepository;
_asyncExecuter = asyncExecuter;
}
public async Task<ListResultDto<ProductDto>> GetListAsync(string name)
{
//Create the query
var query = _productRepository
.Where(p => p.Name.Contains(name))
.OrderBy(p => p.Name);
//Run the query asynchronously
List<Product> products = await _asyncExecuter.ToListAsync(query);
//...
}
}
}
````
> `ApplicationService` 和 `DomainService` 基类已经预属性注入了 `AsyncExecuter` 属性,所以你可直接使用.
ABP框架使用实际数据库提供程序的API异步执行查询.虽然这不是执行查询的常见方式,但它是使用异步API而不依赖于数据库提供者的最佳方式.
此方法建议;
* 如果你正在构建一个没有数据库提供程序集成包的**可重用库**,但是在某些情况下需要执行 `IQueryable<T>`对象.
For example, ABP Framework uses the `IAsyncQueryableExecuter` in the `CrudAppService` base class (see the [application services](Application-Services.md) document).
例如,ABP框架在 `CrudAppService` 基类中(参阅[应用程序](Application-Services.md)文档)使用 `IAsyncQueryableExecuter`.

3
docs/zh-Hans/SignalR-Integration.md

@ -234,4 +234,5 @@ ABP框架不会更改SignalR. 就像在其他ASP.NET Core应用程序中一样,
## 另请参阅
* [微软SignalR文档](https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction)
* [微软SignalR文档](https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction)
* [使用ABP,SignalR和RabbitMQ在分布式体系结构中的实时消息传递](https://volosoft.com/blog/RealTime-Messaging-Distributed-Architecture-Abp-SingalR-RabbitMQ)

2
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/DefaultContainer.cs

@ -3,6 +3,6 @@
[BlobContainerName(Name)]
public class DefaultContainer
{
public const string Name = "Default";
public const string Name = "default";
}
}

15
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AbpDistributedEntityEventOptions.cs

@ -0,0 +1,15 @@
namespace Volo.Abp.Domain.Entities.Events.Distributed
{
public class AbpDistributedEntityEventOptions
{
public IAutoEntityDistributedEventSelectorList AutoEventSelectors { get; }
public EtoMappingDictionary EtoMappings { get; set; }
public AbpDistributedEntityEventOptions()
{
AutoEventSelectors = new AutoEntityDistributedEventSelectorList();
EtoMappings = new EtoMappingDictionary();
}
}
}

12
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorList.cs

@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace Volo.Abp.Domain.Entities.Events.Distributed
{
public class AutoEntityDistributedEventSelectorList : List<NamedTypeSelector>, IAutoEntityDistributedEventSelectorList
{
public bool RemoveByName(string name)
{
return RemoveAll(s => s.Name == name) > 0;
}
}
}

78
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorListExtensions.cs

@ -0,0 +1,78 @@
using System;
using System.Linq;
using JetBrains.Annotations;
namespace Volo.Abp.Domain.Entities.Events.Distributed
{
public static class AutoEntityDistributedEventSelectorListExtensions
{
public const string AllEntitiesSelectorName = "All";
public static void AddNamespace([NotNull] this IAutoEntityDistributedEventSelectorList selectors, [NotNull] string namespaceName)
{
Check.NotNull(selectors, nameof(selectors));
var selectorName = "Namespace:" + namespaceName;
if (selectors.Any(s => s.Name == selectorName))
{
return;
}
selectors.Add(
new NamedTypeSelector(
selectorName,
t => t.FullName?.StartsWith(namespaceName) ?? false
)
);
}
/// <summary>
/// Adds a specific entity type and the types derived from that entity type.
/// </summary>
/// <typeparam name="TEntity">Type of the entity</typeparam>
public static void Add<TEntity>([NotNull] this IAutoEntityDistributedEventSelectorList selectors)
where TEntity : IEntity
{
Check.NotNull(selectors, nameof(selectors));
var selectorName = "Entity:" + typeof(TEntity).FullName;
if (selectors.Any(s => s.Name == selectorName))
{
return;
}
selectors.Add(
new NamedTypeSelector(
selectorName,
t => typeof(TEntity).IsAssignableFrom(t)
)
);
}
/// <summary>
/// Adds all entity types.
/// </summary>
public static void AddAll([NotNull] this IAutoEntityDistributedEventSelectorList selectors)
{
Check.NotNull(selectors, nameof(selectors));
if (selectors.Any(s => s.Name == AllEntitiesSelectorName))
{
return;
}
selectors.Add(
new NamedTypeSelector(
AllEntitiesSelectorName,
t => typeof(IEntity).IsAssignableFrom(t)
)
);
}
public static bool IsMatch([NotNull] this IAutoEntityDistributedEventSelectorList selectors, Type entityType)
{
Check.NotNull(selectors, nameof(selectors));
return selectors.Any(s => s.Predicate(entityType));
}
}
}

6
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityToEtoMapper.cs

@ -3,7 +3,6 @@ using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.ObjectMapping;
namespace Volo.Abp.Domain.Entities.Events.Distributed
@ -11,10 +10,11 @@ namespace Volo.Abp.Domain.Entities.Events.Distributed
public class EntityToEtoMapper : IEntityToEtoMapper, ITransientDependency
{
protected IHybridServiceScopeFactory HybridServiceScopeFactory { get; }
protected AbpDistributedEventBusOptions Options { get; }
protected AbpDistributedEntityEventOptions Options { get; }
public EntityToEtoMapper(
IOptions<AbpDistributedEventBusOptions> options,
IOptions<AbpDistributedEntityEventOptions> options,
IHybridServiceScopeFactory hybridServiceScopeFactory)
{
HybridServiceScopeFactory = hybridServiceScopeFactory;

3
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/EtoMappingDictionary.cs → framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionary.cs

@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
using Volo.Abp.EventBus.Distributed;
namespace Volo.Abp.EventBus.Distributed
namespace Volo.Abp.Domain.Entities.Events.Distributed
{
public class EtoMappingDictionary : Dictionary<Type, EtoMappingDictionaryItem>
{

2
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/EtoMappingDictionaryItem.cs → framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionaryItem.cs

@ -1,6 +1,6 @@
using System;
namespace Volo.Abp.EventBus.Distributed
namespace Volo.Abp.Domain.Entities.Events.Distributed
{
public class EtoMappingDictionaryItem
{

9
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/IAutoEntityDistributedEventSelectorList.cs

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Volo.Abp.Domain.Entities.Events.Distributed
{
public interface IAutoEntityDistributedEventSelectorList : IList<NamedTypeSelector>
{
bool RemoveByName(string name);
}
}

74
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events.Distributed;
@ -22,13 +23,16 @@ namespace Volo.Abp.Domain.Entities.Events
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IEntityToEtoMapper EntityToEtoMapper { get; }
protected AbpDistributedEntityEventOptions DistributedEntityEventOptions { get; }
public EntityChangeEventHelper(
IUnitOfWorkManager unitOfWorkManager,
IEntityToEtoMapper entityToEtoMapper)
IEntityToEtoMapper entityToEtoMapper,
IOptions<AbpDistributedEntityEventOptions> distributedEntityEventOptions)
{
UnitOfWorkManager = unitOfWorkManager;
EntityToEtoMapper = entityToEtoMapper;
DistributedEntityEventOptions = distributedEntityEventOptions.Value;
LocalEventBus = NullLocalEventBus.Instance;
DistributedEventBus = NullDistributedEventBus.Instance;
@ -65,18 +69,32 @@ namespace Volo.Abp.Domain.Entities.Events
false
);
var eto = EntityToEtoMapper.Map(entity);
if (eto != null)
if (ShouldPublishDistributedEventForEntity(entity))
{
await TriggerEventWithEntity(
DistributedEventBus,
typeof(EntityCreatedEto<>),
eto,
false
);
var eto = EntityToEtoMapper.Map(entity);
if (eto != null)
{
await TriggerEventWithEntity(
DistributedEventBus,
typeof(EntityCreatedEto<>),
eto,
false
);
}
}
}
private bool ShouldPublishDistributedEventForEntity(object entity)
{
return DistributedEntityEventOptions
.AutoEventSelectors
.IsMatch(
ProxyHelper
.UnProxy(entity)
.GetType()
);
}
public virtual async Task TriggerEntityUpdatingEventAsync(object entity)
{
await TriggerEventWithEntity(
@ -96,15 +114,18 @@ namespace Volo.Abp.Domain.Entities.Events
false
);
var eto = EntityToEtoMapper.Map(entity);
if (eto != null)
if (ShouldPublishDistributedEventForEntity(entity))
{
await TriggerEventWithEntity(
DistributedEventBus,
typeof(EntityUpdatedEto<>),
eto,
false
);
var eto = EntityToEtoMapper.Map(entity);
if (eto != null)
{
await TriggerEventWithEntity(
DistributedEventBus,
typeof(EntityUpdatedEto<>),
eto,
false
);
}
}
}
@ -127,15 +148,18 @@ namespace Volo.Abp.Domain.Entities.Events
false
);
var eto = EntityToEtoMapper.Map(entity);
if (eto != null)
if (ShouldPublishDistributedEventForEntity(entity))
{
await TriggerEventWithEntity(
DistributedEventBus,
typeof(EntityDeletedEto<>),
EntityToEtoMapper.Map(entity),
false
);
var eto = EntityToEtoMapper.Map(entity);
if (eto != null)
{
await TriggerEventWithEntity(
DistributedEventBus,
typeof(EntityDeletedEto<>),
eto,
false
);
}
}
}

2
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/AbpDistributedEventBusOptions.cs

@ -5,12 +5,10 @@ namespace Volo.Abp.EventBus.Distributed
public class AbpDistributedEventBusOptions
{
public ITypeList<IEventHandler> Handlers { get; }
public EtoMappingDictionary EtoMappings { get; set; }
public AbpDistributedEventBusOptions()
{
Handlers = new TypeList<IEventHandler>();
EtoMappings = new EtoMappingDictionary();
}
}
}

5
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs

@ -4,7 +4,7 @@ using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.AutoMapper;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.TestApp.Application.Dto;
using Volo.Abp.Threading;
@ -45,8 +45,9 @@ namespace Volo.Abp.TestApp
private void ConfigureDistributedEventBus()
{
Configure<AbpDistributedEventBusOptions>(options =>
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.AutoEventSelectors.Add<Person>();
options.EtoMappings.Add<Person, PersonEto>();
});
}

4
modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs

@ -1,7 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Domain;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Modularity;
using Volo.Blogging.Blogs;
using Volo.Blogging.Comments;
@ -25,7 +25,7 @@ namespace Volo.Blogging
options.AddProfile<BloggingDomainMappingProfile>(validate: true);
});
Configure<AbpDistributedEventBusOptions>(options =>
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.EtoMappings.Add<Blog, BlogEto>(typeof(BloggingDomainModule));
options.EtoMappings.Add<Comment, CommentEto>(typeof(BloggingDomainModule));

22
modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/GetAllInput.cs

@ -12,10 +12,28 @@ namespace Volo.Docs.Admin.Documents
[StringLength(DocumentConsts.MaxNameLength)]
public string Name { get; set; }
[StringLength(DocumentConsts.MaxVersionNameLength)]
public string Version { get; set; }
[StringLength(DocumentConsts.MaxLanguageCodeNameLength)]
public string LanguageCode { get; set; }
[StringLength(DocumentConsts.MaxVersionNameLength)]
public string Version { get; set; }
[StringLength(DocumentConsts.MaxFileNameNameLength)]
public string FileName { get; set; }
[StringLength(DocumentConsts.MaxFormatNameLength)]
public string Format { get; set; }
public DateTime? CreationTimeMin { get; set; }
public DateTime? CreationTimeMax { get; set; }
public DateTime? LastUpdatedTimeMin { get; set; }
public DateTime? LastUpdatedTimeMax { get; set; }
public DateTime? LastSignificantUpdateTimeMin { get; set; }
public DateTime? LastSignificantUpdateTimeMax { get; set; }
public DateTime? LastCachedTimeMin { get; set; }
public DateTime? LastCachedTimeMax { get; set; }
}
}

12
modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json

@ -43,6 +43,16 @@
"ReIndexDocumentConfirmation": "Are you sure you want to reindex this item?",
"DeleteDocumentFromDbConfirmation": "Are you sure you want to delete this item from database?",
"DeleteFromDatabase": "Delete from database",
"Deleted": "Deleted"
"Deleted": "Deleted",
"Search": "Search",
"StartDate": "Start date",
"EndDate": "End date",
"CreationTime": "Creation time",
"LastUpdateTime": "Last update",
"LastSignificantUpdateTime": "Last significant update",
"Version": "Version",
"LanguageCode": "Language code",
"FileName": "File name",
"LastCachedTime": "Cache time"
}
}

36
modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs

@ -137,20 +137,40 @@ namespace Volo.Docs.Admin.Documents
public async Task<PagedResultDto<DocumentDto>> GetAllAsync(GetAllInput input)
{
var totalCount = await _documentRepository.GetAllCountAsync(
projectId: input.ProjectId,
name: input.Name,
version: input.Version,
languageCode: input.LanguageCode,
sorting: input.Sorting,
maxResultCount: input.MaxResultCount,
skipCount: input.SkipCount
);
projectId: input.ProjectId,
name: input.Name,
version: input.Version,
languageCode: input.LanguageCode,
fileName: input.FileName,
format: input.Format,
creationTimeMin: input.CreationTimeMin,
creationTimeMax: input.CreationTimeMax,
lastUpdatedTimeMin: input.LastUpdatedTimeMin,
lastUpdatedTimeMax: input.LastUpdatedTimeMax,
lastSignificantUpdateTimeMin: input.LastSignificantUpdateTimeMin,
lastSignificantUpdateTimeMax: input.LastSignificantUpdateTimeMax,
lastCachedTimeMin: input.LastCachedTimeMin,
lastCachedTimeMax: input.LastCachedTimeMax,
sorting: input.Sorting,
maxResultCount: input.MaxResultCount,
skipCount: input.SkipCount
);
var docs = await _documentRepository.GetAllAsync(
projectId: input.ProjectId,
name: input.Name,
version: input.Version,
languageCode: input.LanguageCode,
fileName: input.FileName,
format: input.Format,
creationTimeMin: input.CreationTimeMin,
creationTimeMax: input.CreationTimeMax,
lastUpdatedTimeMin: input.LastUpdatedTimeMin,
lastUpdatedTimeMax: input.LastUpdatedTimeMax,
lastSignificantUpdateTimeMin: input.LastSignificantUpdateTimeMin,
lastSignificantUpdateTimeMax: input.LastSignificantUpdateTimeMax,
lastCachedTimeMin: input.LastCachedTimeMin,
lastCachedTimeMax: input.LastCachedTimeMax,
sorting: input.Sorting,
maxResultCount: input.MaxResultCount,
skipCount: input.SkipCount

219
modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml

@ -22,31 +22,194 @@
<abp-script src="/Pages/Docs/Admin/Documents/index.js" />
}
<abp-card>
<abp-card-header>
<abp-row>
<h2>Filters ...</h2>
@*<abp-column size-md="_6" class="text-right">
<abp-button button-type="Primary" icon="plus" text="@L["ReIndexAllProjects"].Value" id="ReIndexAllProjects" />
</abp-column>*@
</abp-row>
</abp-card-header>
<abp-card-body>
<abp-table striped-rows="true" id="DocumentsTable" class="nowrap">
<thead>
<tr>
<th>@L["Actions"]</th>
<th>@L["Name"]</th>
<th>@L["Version"]</th>
<th>@L["LanguageCode"]</th>
<th>@L["FileName"]</th>
<th>@L["Format"]</th>
<th>@L["CreationTime"]</th>
<th>@L["LastUpdatedTime"]</th>
<th>@L["LastSignificantUpdateTime"]</th>
<th>@L["LastCachedTime"]</th>
</tr>
</thead>
</abp-table>
</abp-card-body>
</abp-card>
@section styles {
<abp-style src="/Pages/Docs/Admin/Documents/index.min.css" />
}
<div id="DocumentsContainer">
<abp-card>
<abp-card-header>
<form class="form-inline" autocomplete="off" id="FilterForm">
<div class="form-row">
<div class="col-auto">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">@L["Name"].Value</div>
</div>
<input type="text"
id="Name"
name="Name"
class="form-control mr-sm-2">
</div>
</div>
<div class="col-auto">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">@L["Version"].Value</div>
</div>
<input type="text"
id="Version"
name="Version"
class="form-control mr-sm-2">
</div>
</div>
<div class="col-auto">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">@L["LanguageCode"].Value</div>
</div>
<input type="text"
id="LanguageCode"
name="LanguageCode"
class="form-control mr-sm-2">
</div>
</div>
<div class="col-auto">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">@L["FileName"].Value</div>
</div>
<input type="text"
id="FileName"
name="FileName"
class="form-control mr-sm-2">
</div>
</div>
<div class="col-auto">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">@L["Format"].Value</div>
</div>
<input type="text"
id="Format"
name="Format"
class="form-control mr-sm-2">
</div>
</div>
<div class="col-auto">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">@L["CreationTime"].Value</div>
</div>
<span>
<input type="date"
id="CreationTimeMin"
name="CreationTimeMin"
class="form-control datepicker"
placeholder="@L["StartDate"]">
<span>-</span>
<input type="date"
id="CreationTimeMax"
name="CreationTimeMax"
placeholder="@L["EndDate"]"
class="form-control datepicker">
</span>
</div>
</div>
<div class="col-auto">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">@L["LastUpdateTime"].Value</div>
</div>
<span>
<input type="date"
id="LastUpdatedTimeMin"
name="LastUpdatedTimeMin"
class="form-control datepicker"
placeholder="@L["StartDate"]">
<span>-</span>
<input type="date"
id="LastUpdatedTimeMax"
name="LastUpdatedTimeMax"
placeholder="@L["EndDate"]"
class="form-control datepicker">
</span>
</div>
</div>
<div class="col-auto">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">@L["LastSignificantUpdateTime"].Value</div>
</div>
<span>
<input type="date"
id="LastSignificantUpdateTimeMin"
name="LastSignificantUpdateTimeMin"
class="form-control datepicker"
placeholder="@L["StartDate"]">
<span>-</span>
<input type="date"
id="LastSignificantUpdateTimeMax"
name="LastSignificantUpdateTimeMax"
placeholder="@L["EndDate"]"
class="form-control datepicker">
</span>
</div>
</div>
<div class="col-auto">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">@L["LastCachedTime"].Value</div>
</div>
<span>
<input type="date"
id="LastCachedTimeMin"
name="LastCachedTimeMin"
class="form-control datepicker"
placeholder="@L["StartDate"]">
<span>-</span>
<input type="date"
id="LastCachedTimeMax"
name="LastCachedTimeMax"
placeholder="@L["EndDate"]"
class="form-control datepicker">
</span>
</div>
</div>
<div class="col-auto">
<abp-button button-type="Primary" icon="search" id="SearchButton" style="line-height: 25px;" text="@L["Search"].Value"></abp-button>
</div>
</div>
</form>
</abp-card-header>
<abp-card-body>
<abp-table striped-rows="true" id="DocumentsTable" class="nowrap">
<thead>
<tr>
<th>@L["Actions"]</th>
<th>@L["Name"]</th>
<th>@L["Version"]</th>
<th>@L["LanguageCode"]</th>
<th>@L["FileName"]</th>
<th>@L["Format"]</th>
<th>@L["CreationTime"]</th>
<th>@L["LastUpdatedTime"]</th>
<th>@L["LastSignificantUpdateTime"]</th>
<th>@L["LastCachedTime"]</th>
</tr>
</thead>
</abp-table>
</abp-card-body>
</abp-card>
</div>

3
modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs

@ -1,6 +1,9 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Volo.Docs.Documents;
namespace Volo.Docs.Admin.Pages.Docs.Admin.Documents
{

3
modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.css

@ -0,0 +1,3 @@
#DocumentsContainer .datepicker {
display: inline-block !important;
width: 7rem !important; }

71
modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js

@ -1,8 +1,32 @@
$(function () {
var l = abp.localization.getResource('Docs');
var service = window.volo.docs.admin.documentsAdmin;
var _dataTable = $('#DocumentsTable').DataTable(abp.libs.datatables.normalizeConfiguration({
var getFormattedDate = function ($datePicker) {
return $datePicker.data().datepicker.getFormattedDate("yyyy-mm-dd");
};
var getFilter = function () {
return {
projectId: $("#ProjectId").val(),
name: $("#Name").val(),
version: $("#Version").val(),
languageCode: $("#LanguageCode").val(),
fileName: $("#FileName").val(),
format: $("#Format").val(),
creationTimeMin: getFormattedDate($("#CreationTimeMin")),
creationTimeMax: getFormattedDate($("#CreationTimeMax")),
lastUpdatedTimeMin: getFormattedDate($("#LastUpdatedTimeMin")),
lastUpdatedTimeMax: getFormattedDate($("#LastUpdatedTimeMax")),
lastSignificantUpdateTimeMin: getFormattedDate($("#LastSignificantUpdateTimeMin")),
lastSignificantUpdateTimeMax: getFormattedDate($("#LastSignificantUpdateTimeMax")),
lastCachedTimeMin: getFormattedDate($("#LastCachedTimeMin")),
lastCachedTimeMax: getFormattedDate($("#LastCachedTimeMax"))
};
};
var dataTable = $('#DocumentsTable').DataTable(abp.libs.datatables.normalizeConfiguration({
processing: true,
serverSide: true,
scrollX: true,
@ -10,7 +34,7 @@
searching: false,
autoWidth: false,
scrollCollapse: true,
ajax: abp.libs.datatables.createAjax(volo.docs.admin.documentsAdmin.getAll),
ajax: abp.libs.datatables.createAjax(service.getAll, getFilter),
columnDefs: [
{
rowAction: {
@ -21,11 +45,10 @@
visible: abp.auth.isGranted('Docs.Admin.Documents'),
confirmMessage: function (data) { return l('RemoveFromCacheConfirmation'); },
action: function (data) {
volo.docs.admin.documentsAdmin
.removeFromCache(data.record.id)
service.removeFromCache(data.record.id)
.then(function () {
abp.message.success(l('RemovedFromCache'));
_dataTable.ajax.reload();
dataTable.ajax.reload();
});
}
},
@ -34,11 +57,10 @@
visible: abp.auth.isGranted('Docs.Admin.Documents'),
confirmMessage: function (data) { return l('ReIndexDocumentConfirmation'); },
action: function (data) {
volo.docs.admin.documentsAdmin
.reindex(data.record.id)
service.reindex(data.record.id)
.then(function () {
abp.message.success(l('ReindexCompleted'));
_dataTable.ajax.reload();
dataTable.ajax.reload();
});
}
},
@ -47,11 +69,10 @@
visible: abp.auth.isGranted('Docs.Admin.Documents'),
confirmMessage: function (data) { return l('DeleteDocumentFromDbConfirmation'); },
action: function (data) {
volo.docs.admin.documentsAdmin
.deleteFromDatabase(data.record.id)
service.deleteFromDatabase(data.record.id)
.then(function () {
abp.message.success(l('Deleted'));
_dataTable.ajax.reload();
dataTable.ajax.reload();
});
}
}
@ -76,14 +97,7 @@
},
{
target: 5,
data: "format",
render: function (data) {
if (data === 'md') {
return 'markdown';
}
return data;
}
data: "format"
},
{
target: 6,
@ -136,18 +150,15 @@
]
}));
$("#FilterForm input[type='text']").keypress(function (e) {
if (e.which === 13) {
dataTable.ajax.reload();
}
});
$("#ReIndexAllProjects").click(function (event) {
abp.message.confirm(l('ReIndexAllProjectConfirmationMessage'))
.done(function (accepted) {
if (accepted) {
volo.docs.admin.projectsAdmin
.reindexAll()
.then(function () {
abp.message.success(l('SuccessfullyReIndexAllProject'));
});
}
});
$("#SearchButton").click(function (e) {
e.preventDefault();
dataTable.ajax.reload();
});
});

1
modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.min.css

@ -0,0 +1 @@
#DocumentsContainer .datepicker{display:inline-block !important;width:7rem !important;}

6
modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.scss

@ -0,0 +1,6 @@
#DocumentsContainer {
.datepicker {
display: inline-block !important;
width: 7rem !important;
}
}

8
modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj

@ -13,13 +13,16 @@
<TypeScriptToolsVersion>2.8</TypeScriptToolsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommonMark.NET" Version="0.15.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Bundling\Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Packages\Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj" />
<ProjectReference Include="..\Volo.Docs.Admin.HttpApi\Volo.Docs.Admin.HttpApi.csproj" />
<PackageReference Include="CommonMark.NET" Version="0.15.1" />
</ItemGroup>
<ItemGroup>
@ -29,8 +32,7 @@
<Content Remove="Pages\**\*.js" />
<Content Remove="Properties\launchSettings.json" />
<Content Remove="compilerconfig.json" />
<Content Remove="compilerconfig.json.defaults" />
<None Remove="Pages\Docs\Admin\Documents\index.js" />
<Content Remove="compilerconfig.json.defaults" />
<None Include="compilerconfig.json" />
<None Include="Properties\launchSettings.json" />
</ItemGroup>

6
modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json

@ -0,0 +1,6 @@
[
{
"outputFile": "Pages/Docs/Admin/Documents/index.css",
"inputFile": "Pages/Docs/Admin/Documents/index.scss"
}
]

63
modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json.defaults

@ -0,0 +1,63 @@
{
"compilers": {
"less": {
"autoPrefix": "",
"cssComb": "none",
"ieCompat": true,
"strictMath": false,
"strictUnits": false,
"relativeUrls": true,
"rootPath": "",
"sourceMapRoot": "",
"sourceMapBasePath": "",
"sourceMap": false
},
"sass": {
"autoPrefix": "",
"includePath": "",
"indentType": "space",
"indentWidth": 2,
"outputStyle": "nested",
"Precision": 5,
"relativeUrls": true,
"sourceMapRoot": "",
"lineFeed": "",
"sourceMap": false
},
"stylus": {
"sourceMap": false
},
"babel": {
"sourceMap": false
},
"coffeescript": {
"bare": false,
"runtimeMode": "node",
"sourceMap": false
},
"handlebars": {
"root": "",
"noBOM": false,
"name": "",
"namespace": "",
"knownHelpersOnly": false,
"forcePartial": false,
"knownHelpers": [],
"commonjs": "",
"amd": false,
"sourceMap": false
}
},
"minifiers": {
"css": {
"enabled": true,
"termSemicolons": true,
"gzip": false
},
"javascript": {
"enabled": true,
"termSemicolons": true,
"gzip": false
}
}
}

4
modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs

@ -4,7 +4,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.AutoMapper;
using Volo.Abp.Domain;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Threading;
@ -34,7 +34,7 @@ namespace Volo.Docs
options.AddProfile<DocsDomainMappingProfile>(validate: true);
});
Configure<AbpDistributedEventBusOptions>(options =>
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.EtoMappings.Add<Document, DocumentEto>(typeof(DocsDomainModule));
options.EtoMappings.Add<Project, ProjectEto>(typeof(DocsDomainModule));

23
modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentRepository.cs

@ -23,10 +23,21 @@ namespace Volo.Docs.Documents
string version,
CancellationToken cancellationToken = default);
Task<List<Document>> GetAllAsync(Guid? projectId,
Task<List<Document>> GetAllAsync(
Guid? projectId,
string name,
string version,
string languageCode,
string fileName,
string format,
DateTime? creationTimeMin,
DateTime? creationTimeMax,
DateTime? lastUpdatedTimeMin,
DateTime? lastUpdatedTimeMax,
DateTime? lastSignificantUpdateTimeMin,
DateTime? lastSignificantUpdateTimeMax,
DateTime? lastCachedTimeMin,
DateTime? lastCachedTimeMax,
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
@ -37,6 +48,16 @@ namespace Volo.Docs.Documents
string name,
string version,
string languageCode,
string fileName,
string format,
DateTime? creationTimeMin,
DateTime? creationTimeMax,
DateTime? lastUpdatedTimeMin,
DateTime? lastUpdatedTimeMax,
DateTime? lastSignificantUpdateTimeMin,
DateTime? lastSignificantUpdateTimeMax,
DateTime? lastCachedTimeMin,
DateTime? lastCachedTimeMax,
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,

103
modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Documents/EFCoreDocumentRepository.cs

@ -24,16 +24,44 @@ namespace Volo.Docs.Documents
return await DbSet.Where(d => d.ProjectId == projectId).ToListAsync(cancellationToken: cancellationToken);
}
public async Task<List<Document>> GetAllAsync(Guid? projectId,
public async Task<List<Document>> GetAllAsync(
Guid? projectId,
string name,
string version,
string languageCode,
string fileName,
string format,
DateTime? creationTimeMin,
DateTime? creationTimeMax,
DateTime? lastUpdatedTimeMin,
DateTime? lastUpdatedTimeMax,
DateTime? lastSignificantUpdateTimeMin,
DateTime? lastSignificantUpdateTimeMax,
DateTime? lastCachedTimeMin,
DateTime? lastCachedTimeMax,
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
CancellationToken cancellationToken = default)
{
var query = ApplyFilterForGetAll(DbSet, projectId, name, version, languageCode);
var query = ApplyFilterForGetAll(
DbSet,
projectId: projectId,
name: name,
version: version,
languageCode: languageCode,
format: format,
fileName: fileName,
creationTimeMin: creationTimeMin,
creationTimeMax: creationTimeMax,
lastUpdatedTimeMin: lastUpdatedTimeMin,
lastUpdatedTimeMax: lastUpdatedTimeMax,
lastSignificantUpdateTimeMin: lastSignificantUpdateTimeMin,
lastSignificantUpdateTimeMax: lastSignificantUpdateTimeMax,
lastCachedTimeMin: lastCachedTimeMin,
lastCachedTimeMax: lastCachedTimeMax
);
query = query.OrderBy(string.IsNullOrWhiteSpace(sorting) ? nameof(Document.Name) : sorting);
return await query.PageBy(skipCount, maxResultCount).ToListAsync(cancellationToken);
}
@ -43,12 +71,39 @@ namespace Volo.Docs.Documents
string name,
string version,
string languageCode,
string fileName,
string format,
DateTime? creationTimeMin,
DateTime? creationTimeMax,
DateTime? lastUpdatedTimeMin,
DateTime? lastUpdatedTimeMax,
DateTime? lastSignificantUpdateTimeMin,
DateTime? lastSignificantUpdateTimeMax,
DateTime? lastCachedTimeMin,
DateTime? lastCachedTimeMax,
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
CancellationToken cancellationToken = default)
{
var query = ApplyFilterForGetAll(DbSet, projectId, name, version, languageCode);
var query = ApplyFilterForGetAll(
DbSet,
projectId: projectId,
name: name,
version: version,
languageCode: languageCode,
format: format,
fileName: fileName,
creationTimeMin: creationTimeMin,
creationTimeMax: creationTimeMax,
lastUpdatedTimeMin: lastUpdatedTimeMin,
lastUpdatedTimeMax: lastUpdatedTimeMax,
lastSignificantUpdateTimeMin: lastSignificantUpdateTimeMin,
lastSignificantUpdateTimeMax: lastSignificantUpdateTimeMax,
lastCachedTimeMin: lastCachedTimeMin,
lastCachedTimeMax: lastCachedTimeMax
);
return await query.LongCountAsync(GetCancellationToken(cancellationToken));
}
@ -81,13 +136,47 @@ namespace Volo.Docs.Documents
string name,
string version,
string languageCode,
string fileName,
string format,
DateTime? creationTimeMin,
DateTime? creationTimeMax,
DateTime? lastUpdatedTimeMin,
DateTime? lastUpdatedTimeMax,
DateTime? lastSignificantUpdateTimeMin,
DateTime? lastSignificantUpdateTimeMax,
DateTime? lastCachedTimeMin,
DateTime? lastCachedTimeMax,
CancellationToken cancellationToken = default)
{
return DbSet
.WhereIf(projectId.HasValue, d => d.ProjectId == projectId.Value)
.WhereIf(name != null, d => d.Name != null && d.Name.Contains(name))
.WhereIf(version != null, d => d.Version != null && d.Version == version)
.WhereIf(languageCode != null, d => d.LanguageCode != null && d.LanguageCode == languageCode);
.WhereIf(projectId.HasValue,
d => d.ProjectId == projectId.Value)
.WhereIf(name != null,
d => d.Name != null && d.Name.Contains(name))
.WhereIf(version != null,
d => d.Version != null && d.Version == version)
.WhereIf(languageCode != null,
d => d.LanguageCode != null && d.LanguageCode == languageCode)
.WhereIf(fileName != null,
d => d.FileName != null && d.FileName.Contains(fileName))
.WhereIf(format != null,
d => d.Format != null && d.Format == format)
.WhereIf(creationTimeMin.HasValue,
d => d.CreationTime.Date >= creationTimeMin.Value.Date)
.WhereIf(creationTimeMax.HasValue,
d => d.CreationTime.Date <= creationTimeMax.Value.Date)
.WhereIf(lastUpdatedTimeMin.HasValue,
d => d.LastUpdatedTime.Date >= lastUpdatedTimeMin.Value.Date)
.WhereIf(lastUpdatedTimeMax.HasValue,
d => d.LastUpdatedTime.Date <= lastUpdatedTimeMax.Value.Date)
.WhereIf(lastSignificantUpdateTimeMin.HasValue,
d => d.LastSignificantUpdateTime != null && d.LastSignificantUpdateTime.Value.Date >= lastSignificantUpdateTimeMin.Value.Date)
.WhereIf(lastSignificantUpdateTimeMax.HasValue,
d => d.LastSignificantUpdateTime != null && d.LastSignificantUpdateTime.Value.Date <= lastSignificantUpdateTimeMax.Value.Date)
.WhereIf(lastCachedTimeMin.HasValue,
d => d.LastCachedTime.Date >= lastCachedTimeMin.Value.Date)
.WhereIf(lastCachedTimeMax.HasValue,
d => d.LastCachedTime.Date <= lastCachedTimeMax.Value.Date);
}
}
}

124
modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Documents/MongoDocumentRepository.cs

@ -43,33 +43,88 @@ namespace Volo.Docs.Documents
x.Version == version, cancellationToken: cancellationToken);
}
public async Task<List<Document>> GetAllAsync(Guid? projectId,
public async Task<List<Document>> GetAllAsync(
Guid? projectId,
string name,
string version,
string languageCode,
string fileName,
string format,
DateTime? creationTimeMin,
DateTime? creationTimeMax,
DateTime? lastUpdatedTimeMin,
DateTime? lastUpdatedTimeMax,
DateTime? lastSignificantUpdateTimeMin,
DateTime? lastSignificantUpdateTimeMax,
DateTime? lastCachedTimeMin,
DateTime? lastCachedTimeMax,
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
CancellationToken cancellationToken = default)
{
return await
ApplyFilterForGetAll(GetMongoQueryable(), projectId, name, version, languageCode)
.OrderBy(string.IsNullOrWhiteSpace(sorting) ? "name asc" : sorting).As<IMongoQueryable<Document>>()
.PageBy<Document, IMongoQueryable<Document>>(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
ApplyFilterForGetAll(
GetMongoQueryable(),
projectId: projectId,
name: name,
version: version,
languageCode: languageCode,
format: format,
fileName: fileName,
creationTimeMin: creationTimeMin,
creationTimeMax: creationTimeMax,
lastUpdatedTimeMin: lastUpdatedTimeMin,
lastUpdatedTimeMax: lastUpdatedTimeMax,
lastSignificantUpdateTimeMin: lastSignificantUpdateTimeMin,
lastSignificantUpdateTimeMax: lastSignificantUpdateTimeMax,
lastCachedTimeMin: lastCachedTimeMin,
lastCachedTimeMax: lastCachedTimeMax)
.OrderBy(string.IsNullOrWhiteSpace(sorting) ? "name asc" : sorting).As<IMongoQueryable<Document>>()
.PageBy<Document, IMongoQueryable<Document>>(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<long> GetAllCountAsync(Guid? projectId,
public async Task<long> GetAllCountAsync(
Guid? projectId,
string name,
string version,
string languageCode,
string fileName,
string format,
DateTime? creationTimeMin,
DateTime? creationTimeMax,
DateTime? lastUpdatedTimeMin,
DateTime? lastUpdatedTimeMax,
DateTime? lastSignificantUpdateTimeMin,
DateTime? lastSignificantUpdateTimeMax,
DateTime? lastCachedTimeMin,
DateTime? lastCachedTimeMax,
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
CancellationToken cancellationToken = default)
{
return await
ApplyFilterForGetAll(GetMongoQueryable(), projectId, name, version, languageCode)
ApplyFilterForGetAll(
GetMongoQueryable(),
projectId: projectId,
name: name,
version: version,
languageCode: languageCode,
format: format,
fileName: fileName,
creationTimeMin: creationTimeMin,
creationTimeMax: creationTimeMax,
lastUpdatedTimeMin: lastUpdatedTimeMin,
lastUpdatedTimeMax: lastUpdatedTimeMax,
lastSignificantUpdateTimeMin: lastSignificantUpdateTimeMin,
lastSignificantUpdateTimeMax: lastSignificantUpdateTimeMax,
lastCachedTimeMin: lastCachedTimeMin,
lastCachedTimeMax: lastCachedTimeMax)
.OrderBy(string.IsNullOrWhiteSpace(sorting) ? "name asc" : sorting).As<IMongoQueryable<Document>>()
.PageBy<Document, IMongoQueryable<Document>>(skipCount, maxResultCount)
.LongCountAsync(GetCancellationToken(cancellationToken));
@ -86,6 +141,16 @@ namespace Volo.Docs.Documents
string name,
string version,
string languageCode,
string fileName,
string format,
DateTime? creationTimeMin,
DateTime? creationTimeMax,
DateTime? lastUpdatedTimeMin,
DateTime? lastUpdatedTimeMax,
DateTime? lastSignificantUpdateTimeMin,
DateTime? lastSignificantUpdateTimeMax,
DateTime? lastCachedTimeMin,
DateTime? lastCachedTimeMax,
CancellationToken cancellationToken = default)
{
if (projectId.HasValue)
@ -108,6 +173,51 @@ namespace Volo.Docs.Documents
query = query.Where(d => d.LanguageCode != null && d.LanguageCode == languageCode);
}
if (fileName != null)
{
query = query.Where(d => d.FileName != null && d.FileName.Contains(fileName));
}
if (creationTimeMin.HasValue)
{
query = query.Where(d => d.CreationTime.Date >= creationTimeMin.Value.Date);
}
if (creationTimeMax.HasValue)
{
query = query.Where(d => d.CreationTime.Date <= creationTimeMax.Value.Date);
}
if (lastUpdatedTimeMin.HasValue)
{
query = query.Where(d => d.LastUpdatedTime.Date >= lastUpdatedTimeMin.Value.Date);
}
if (lastUpdatedTimeMax.HasValue)
{
query = query.Where(d => d.LastUpdatedTime.Date <= lastUpdatedTimeMax.Value.Date);
}
if (lastSignificantUpdateTimeMin.HasValue)
{
query = query.Where(d => d.LastSignificantUpdateTime != null && d.LastSignificantUpdateTime.Value.Date >= lastSignificantUpdateTimeMin.Value.Date);
}
if (lastSignificantUpdateTimeMax.HasValue)
{
query = query.Where(d => d.LastSignificantUpdateTime != null && d.LastSignificantUpdateTime.Value.Date <= lastSignificantUpdateTimeMax.Value.Date);
}
if (lastCachedTimeMin.HasValue)
{
query = query.Where(d => d.LastCachedTime.Date >= lastCachedTimeMin.Value.Date);
}
if (lastCachedTimeMax.HasValue)
{
query = query.Where(d => d.LastCachedTime.Date <= lastCachedTimeMax.Value.Date);
}
return query;
}
}

4
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs

@ -4,7 +4,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Volo.Abp.AutoMapper;
using Volo.Abp.Domain;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
@ -29,7 +29,7 @@ namespace Volo.Abp.Identity
options.AddProfile<IdentityDomainMappingProfile>(validate: true);
});
Configure<AbpDistributedEventBusOptions>(options =>
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.EtoMappings.Add<IdentityUser, UserEto>(typeof(AbpIdentityDomainModule));
options.EtoMappings.Add<IdentityClaimType, IdentityClaimTypeEto>(typeof(AbpIdentityDomainModule));

9
modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs

@ -1,5 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement.Identity;
@ -14,6 +15,14 @@ namespace Volo.Abp.Identity
)]
public class AbpIdentityDomainTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.AutoEventSelectors.Add<IdentityUser>();
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
SeedTestData(context);

15
modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs

@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Shouldly;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Testing.Utils;
using Volo.Abp.Uow;
@ -28,11 +29,17 @@ namespace Volo.Abp.Identity
}
[Fact]
public async Task Should_Register_Handler()
public void Should_Register_Handler()
{
var options = GetRequiredService<IOptions<AbpDistributedEventBusOptions>>().Value;
options.EtoMappings.ShouldContain(m => m.Key == typeof(IdentityUser) && m.Value.EtoType == typeof(UserEto));
options.Handlers.ShouldContain(h => h == typeof(DistributedUserUpdateHandler));
GetRequiredService<IOptions<AbpDistributedEntityEventOptions>>()
.Value
.EtoMappings
.ShouldContain(m => m.Key == typeof(IdentityUser) && m.Value.EtoType == typeof(UserEto));
GetRequiredService<IOptions<AbpDistributedEventBusOptions>>()
.Value
.Handlers
.ShouldContain(h => h == typeof(DistributedUserUpdateHandler));
}
[Fact]

4
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs

@ -6,7 +6,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp.AutoMapper;
using Volo.Abp.BackgroundWorkers;
using Volo.Abp.Caching;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.Clients;
@ -41,7 +41,7 @@ namespace Volo.Abp.IdentityServer
options.AddProfile<IdentityServerAutoMapperProfile>(validate: true);
});
Configure<AbpDistributedEventBusOptions>(options =>
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.EtoMappings.Add<ApiResource, ApiResourceEto>(typeof(AbpIdentityServerDomainModule));
options.EtoMappings.Add<Client, ClientEto>(typeof(AbpIdentityServerDomainModule));

4
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs

@ -2,7 +2,7 @@
using Volo.Abp.AutoMapper;
using Volo.Abp.Data;
using Volo.Abp.Domain;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.UI;
@ -26,7 +26,7 @@ namespace Volo.Abp.TenantManagement
options.AddProfile<AbpTenantManagementDomainMappingProfile>(validate: true);
});
Configure<AbpDistributedEventBusOptions>(options =>
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.EtoMappings.Add<Tenant, TenantEto>();
});

7
npm/ng-packs/packages/core/src/lib/services/list.service.ts

@ -1,6 +1,6 @@
import { Inject, Injectable, OnDestroy, Optional } from '@angular/core';
import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs';
import { debounceTime, shareReplay, switchMap, tap } from 'rxjs/operators';
import { BehaviorSubject, Observable, of, ReplaySubject } from 'rxjs';
import { catchError, debounceTime, filter, shareReplay, switchMap, tap } from 'rxjs/operators';
import { ABP } from '../models/common';
import { PagedResultDto } from '../models/dtos';
import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens/list.token';
@ -88,7 +88,8 @@ export class ListService<QueryParamsType = ABP.PageQueryParams> implements OnDes
this._isLoading$.next(true);
return this.query$.pipe(
switchMap(streamCreatorCallback),
switchMap(query => streamCreatorCallback(query).pipe(catchError(() => of(null)))),
filter(Boolean),
tap(() => this._isLoading$.next(false)),
shareReplay({ bufferSize: 1, refCount: true }),
takeUntilDestroy(this),

13
npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts

@ -36,8 +36,15 @@ export class NgxDatatableListDirective implements OnChanges, OnDestroy, OnInit {
private subscribeToSort() {
const sub = this.table.sort.subscribe(({ sorts: [{ prop, dir }] }) => {
this.list.sortKey = prop;
this.list.sortOrder = dir;
if (prop === this.list.sortKey && this.list.sortOrder === 'desc') {
this.list.sortKey = '';
this.list.sortOrder = '';
this.table.sorts = [];
this.cdRef.detectChanges();
} else {
this.list.sortKey = prop;
this.list.sortOrder = dir;
}
});
this.subscription.add(sub);
}
@ -45,7 +52,7 @@ export class NgxDatatableListDirective implements OnChanges, OnDestroy, OnInit {
private subscribeToIsLoading() {
const sub = this.list.isLoading$.subscribe(loading => {
this.table.loadingIndicator = loading;
this.cdRef.markForCheck();
this.cdRef.detectChanges();
});
this.subscription.add(sub);
}

1
samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs

@ -8,7 +8,6 @@ using ProductManagement;
using StackExchange.Redis;
using Microsoft.OpenApi.Models;
using MsDemo.Shared;
using Swashbuckle.AspNetCore.Swagger;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.OAuth;
using Volo.Abp.AspNetCore.Mvc.Client;

6
samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs

@ -13,6 +13,7 @@ using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Autofac;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.SqlServer;
using Volo.Abp.EventBus.RabbitMq;
@ -77,6 +78,11 @@ namespace IdentityService.Host
{
options.UseSqlServer();
});
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.AutoEventSelectors.Add<IdentityUser>();
});
context.Services.AddStackExchangeRedisCache(options =>
{

Loading…
Cancel
Save