Browse Source

Merge branch 'dev' of https://github.com/abpframework/abp into dev

pull/4797/head
Erol Arkat 6 years ago
parent
commit
16e2c23f1a
  1. 66
      docs/en/Blob-Storing-Minio.md
  2. 2
      docs/en/Blob-Storing.md
  3. 6
      docs/en/Samples/Microservice-Demo.md
  4. 4
      docs/en/docs-nav.json
  5. 66
      docs/zh-Hans/Blob-Storing-Minio.md
  6. 2
      docs/zh-Hans/Blob-Storing.md
  7. 4
      docs/zh-Hans/docs-nav.json
  8. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs
  9. 21
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs
  10. 40
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JQueryValidation/JQueryValidationScriptContributor.cs
  11. 18
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs
  12. 28
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js
  13. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  14. 38
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs
  15. 11
      framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs
  16. 1
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
  17. 10
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs
  18. 11
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml

66
docs/en/Blob-Storing-Minio.md

@ -0,0 +1,66 @@
# BLOB Storing Minio Provider
BLOB Storing Minio Provider can store BLOBs in [MinIO Object storage](https://min.io/).
> Read the [BLOB Storing document](Blob-Storing.md) to understand how to use the BLOB storing system. This document only covers how to configure containers to use a Minio BLOB as the storage provider.
## Installation
Use the ABP CLI to add [Volo.Abp.BlobStoring.Minio](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Minio) NuGet package to your project:
* Install the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) if you haven't installed before.
* Open a command line (terminal) in the directory of the `.csproj` file you want to add the `Volo.Abp.BlobStoring.Minio` package.
* Run `abp add-package Volo.Abp.BlobStoring.Minio` command.
If you want to do it manually, install the [Volo.Abp.BlobStoring.Minio](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Minio) NuGet package to your project and add `[DependsOn(typeof(AbpBlobStoringMinioModule))]` to the [ABP module](Module-Development-Basics.md) class inside your project.
## Configuration
Configuration is done in the `ConfigureServices` method of your [module](Module-Development-Basics.md) class, as explained in the [BLOB Storing document](Blob-Storing.md).
**Example: Configure to use the minio storage provider by default**
````csharp
Configure<AbpBlobStoringOptions>(options =>
{
options.Containerscontainer.UseMinio(minio =>
{
minio.EndPoint = "your minio endPoint";
minio.AccessKey = "your minio accessKey";
minio.SecretKey = "your minio secretKey";
minio.BucketName = "your minio bucketName";
});
});
````
> See the [BLOB Storing document](Blob-Storing.md) to learn how to configure this provider for a specific container.
### Options
* **EndPoint** (string): URL to object storage service. Please refer to MinIO Client SDK for .NET: https://docs.min.io/docs/dotnet-client-quickstart-guide.html
* **AccessKey** (string): Access key is the user ID that uniquely identifies your account.
* **SecretKey** (string): Secret key is the password to your account.
* **BucketName** (string): You can specify the bucket name in MinIO. If this is not specified, it uses the name of the BLOB container defined with the `BlogContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)).MinIO is the defacto standard for S3 compatibility, So MinIO has some **rules for naming bucket**. The [following rules](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html) apply for naming MinIO buckets:
* Bucket names must be between **3** and **63** characters long.
* Bucket names can consist only of **lowercase** letters, numbers, dots (.), and hyphens (-).
* Bucket names must begin and end with a letter or number.
* Bucket names must not be formatted as an IP address (for example, 192.168.5.4).
* Bucket names can't begin with **xn--** (for buckets created after February 2020).
* Bucket names must be unique within a partition.
* Buckets used with Amazon S3 Transfer Acceleration can't have dots (.) in their names. For more information about transfer acceleration, see Amazon S3 Transfer Acceleration.
* **WithSSL** (bool): Default value is `false`,Chain to MinIO Client object to use https instead of http.
* **CreateContainerIfNotExists** (bool): Default value is `false`, If a bucket does not exist in minio, `MinioBlobProvider` will try to create it.
## Minio Blob Name Calculator
Minio Blob Provider organizes BLOB name and implements some conventions. The full name of a BLOB is determined by the following rules by default:
* Appends `host` string if [current tenant](Multi-Tenancy.md) is `null` (or multi-tenancy is disabled for the container - see the [BLOB Storing document](Blob-Storing.md) to learn how to disable multi-tenancy for a container).
* Appends `tenants/<tenant-id>` string if current tenant is not `null`.
* Appends the BLOB name.
## Other Services
* `MinioBlobProvider` is the main service that implements the Minio BLOB storage provider, if you want to override/replace it via [dependency injection](Dependency-Injection.md) (don't replace `IBlobProvider` interface, but replace `MinioBlobProvider` class).
* `IMinioBlobNameCalculator` is used to calculate the full BLOB name (that is explained above). It is implemented by the `DefaultMinioBlobNameCalculator` by default.

2
docs/en/Blob-Storing.md

@ -19,6 +19,8 @@ The ABP Framework has already the following storage provider implementations;
* [File System](Blob-Storing-File-System.md): Stores BLOBs in a folder of the local file system, as standard files. * [File System](Blob-Storing-File-System.md): Stores BLOBs in a folder of the local file system, as standard files.
* [Database](Blob-Storing-Database.md): Stores BLOBs in a database. * [Database](Blob-Storing-Database.md): Stores BLOBs in a database.
* [Azure](Blob-Storing-Azure.md): Stores BLOBs on the [Azure BLOB storage](https://azure.microsoft.com/en-us/services/storage/blobs/). * [Azure](Blob-Storing-Azure.md): Stores BLOBs on the [Azure BLOB storage](https://azure.microsoft.com/en-us/services/storage/blobs/).
* [Aliyun](Blob-Storing-Aliyun.md): Stores BLOBs on the [Aliyun Blob storage](https://help.aliyun.com/product/31815.html).
* [Ninio](Blob-Storing-Minio.md): Stores BLOBs on the [MinIO Object storage](https://min.io/).
More providers will be implemented by the time. You can [request](https://github.com/abpframework/abp/issues/new) it for your favorite provider or [create it yourself](Blob-Storing-Custom-Provider.md) and [contribute](Contribution/Index.md) to the ABP Framework. More providers will be implemented by the time. You can [request](https://github.com/abpframework/abp/issues/new) it for your favorite provider or [create it yourself](Blob-Storing-Custom-Provider.md) and [contribute](Contribution/Index.md) to the ABP Framework.

6
docs/en/Samples/Microservice-Demo.md

@ -43,6 +43,12 @@ To be able to run the solution from source code, following tools should be insta
* [ElasticSearch](https://www.elastic.co/downloads/elasticsearch) 6.6+ * [ElasticSearch](https://www.elastic.co/downloads/elasticsearch) 6.6+
* [Kibana](https://www.elastic.co/downloads/kibana) 6.6+ (optional, recommended to show logs) * [Kibana](https://www.elastic.co/downloads/kibana) 6.6+ (optional, recommended to show logs)
### Running Infrastructure
* Docker-compose is used to run the pre requirements with ease as default. If you don't have it, you can download and start using [Docker for Windows](https://docs.docker.com/docker-for-windows/) from [here](https://docs.docker.com/docker-for-windows/install/) on windows environment.
* Run the command `docker-compose -f docker-compose.infrastructure.yml -f docker-compose.infrastructure.override.yml up -d` at `MicroserviceDemo` directory or run the powershell script `__Run_Infrastructure.ps1` located at `MicroserviceDemo/_run` directory.
* If you don't want to use docker for pre required services and install them on your local development, you need to update `appsettings.json` files of the projects in the MicroserviceDemo solution accordingly.
### Open & Build the Visual Studio Solution ### Open & Build the Visual Studio Solution
* Open the `samples\MicroserviceDemo\MicroserviceDemo.sln` in Visual Studio 2017 (15.9.0+). * Open the `samples\MicroserviceDemo\MicroserviceDemo.sln` in Visual Studio 2017 (15.9.0+).

4
docs/en/docs-nav.json

@ -220,6 +220,10 @@
"text": "Aliyun Provider", "text": "Aliyun Provider",
"path": "Blob-Storing-Aliyun.md" "path": "Blob-Storing-Aliyun.md"
}, },
{
"text": "Minio Provider",
"path": "Blob-Storing-Minio.md"
},
{ {
"text": "Create a Custom Provider", "text": "Create a Custom Provider",
"path": "Blob-Storing-Custom-Provider.md" "path": "Blob-Storing-Custom-Provider.md"

66
docs/zh-Hans/Blob-Storing-Minio.md

@ -0,0 +1,66 @@
# BLOB Storing Minio 提供程序
BLOB Storing Minio提供程序帮助你存储对象到 [MinIO Object storage](https://min.io/),
> 阅读[BLOB存储文档](Blob-Storing.md)了解如何使用BLOB存储系统, 本文档仅介绍如何为容器配置Minio提供程序,
## 安装
使用 ABP CLI 来安装 [Volo.Abp.BlobStoring.Minio](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Minio) NuGet 包到你的项目:
* 如果你没有安装ABP CLI,请先安装 [ABP CLI](https://docs.abp.io/en/abp/latest/CLI),
* 在要添加 `Volo.Abp.BlobStoring.Minio` 包的 `.csproj` 文件目录打开命令行,
* 执行 `abp add-package Volo.Abp.BlobStoring.Minio` 命令,
如果你要手动安装, 通过NuGet安装 [Volo.Abp.BlobStoring.Minio](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Minio) 到你的项目,然后添加 `[DependsOn(typeof(AbpBlobStoringMinioModule))]` 特性到你的 [ABP module](Module-Development-Basics.md) 类上,
## 配置
配置在你的[module](Module-Development-Basics.md)类中的`ConfigureServices`方法中完成,
**例: 配置使用Minio存储**
````csharp
Configure<AbpBlobStoringOptions>(options =>
{
options.Containerscontainer.UseMinio(minio =>
{
minio.EndPoint = "你的 minio endPoint";
minio.AccessKey = "你的 minio accessKey";
minio.SecretKey = "你的 minio secretKey";
minio.BucketName = "你的 minio bucketName";
});
});
````
> 参阅[BLOB存储文档](Blob-Storing.md) 学习如何为指定容器配置提供程序,
### 选项
* **EndPoint** (string): 你的Minio对象存储服务的URL, 查看文档:https://docs.min.io/docs/dotnet-client-quickstart-guide.html
* **AccessKey** (string): Access key是唯一标识你的账户的用户ID,
* **SecretKey** (string): Access key是唯一标识你的账户的用户ID
* **BucketName** (string):你可以指定bucket名称,如果没有指定,将使用 `BlogContainerName` 属性定义的BLOB容器的名称(查阅[BLOB storing document](Blob-Storing.md)),MinIO完全兼容S3标准,所以有一些 **bucket命名规则**,必须符合[规则](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html):
* Bucket名字必须 **3** 到 **63** 字符长度.
* Bucket名字必须是 **小写** 的字母,数字,点号(.), 横杠 (-),
* Bucket名字必须是以数字和字母开头和结尾,
* Bucket名字不能是ip (例如, 192.168.5.4),
* Bucket名字不能以 **xn--** 开头, (2020年2月以后创建),
* Bucket名字必须区块唯一
* Buckets如果使用Amazon S3加速传输名字不能有点号(.),
* **WithSSL** (bool): 默认 `false`,代表使用HTTPS,
* **CreateContainerIfNotExists** (bool): 默认 `false`,如果不存在bucket, `MinioBlobProvider` 将会创建一个,
## Minio BLOB 名称计算器
默认情况下BLOB的全名由以下规则确定:
* 如果当前租户为 `null`(或容器禁用多租户 - 请参阅[BLOB存储文档](Blob-Storing.md) 了解如何禁用容器的多租户),则追加 `host` 字符串,
* 如果当前租户不为 `null`,则追加 `tenants/<tenant-id>` 字符串,
* 追加 BLOB 名称,
## 其他服务
* `MinioBlobProvider` 是实现Minio BLOB存储提供程序的主要服务,如果你想要通过[依赖注入](Dependency-Injection.md)覆盖/替换它(不要替换 `IBlobProvider` 接口,而是替换 `MinioBlobProvider` 类).
* `IMinioBlobNameCalculator` 服务用于计算文件路径. 默认实现是 `DefaultMinioBlobNameCalculator`. 如果你想自定义文件路径计算,可以替换/覆盖它.

2
docs/zh-Hans/Blob-Storing.md

@ -19,6 +19,8 @@ ABP框架已经有以下存储提供程序的实现;
* [File System](Blob-Storing-File-System.md):将BLOB作为标准文件存储在本地文件系统的文件夹中. * [File System](Blob-Storing-File-System.md):将BLOB作为标准文件存储在本地文件系统的文件夹中.
* [Database](Blob-Storing-Database.md): 将BLOB存储在数据库中. * [Database](Blob-Storing-Database.md): 将BLOB存储在数据库中.
* [Azure](Blob-Storing-Azure.md): 将BLOG存储在 [Azure BLOB storage](https://azure.microsoft.com/en-us/services/storage/blobs/)中. * [Azure](Blob-Storing-Azure.md): 将BLOG存储在 [Azure BLOB storage](https://azure.microsoft.com/en-us/services/storage/blobs/)中.
* [Aliyun](Blob-Storing-Aliyun.md): 将BLOB存储在[Aliyun Blob storage](https://help.aliyun.com/product/31815.html)中.
* [Ninio](Blob-Storing-Minio.md): 将BLOB存储在[MinIO Object storage](https://min.io/)中.
以后会实现更多的提供程序,你可以为自己喜欢的提供程序创建[请求](https://github.com/abpframework/abp/issues/new),或者你也可以[自己实现](Blob-Storing-Custom-Provider.md)它并[贡献](Contribution/Index.md)到ABP框架. 以后会实现更多的提供程序,你可以为自己喜欢的提供程序创建[请求](https://github.com/abpframework/abp/issues/new),或者你也可以[自己实现](Blob-Storing-Custom-Provider.md)它并[贡献](Contribution/Index.md)到ABP框架.

4
docs/zh-Hans/docs-nav.json

@ -214,6 +214,10 @@
"text": "Aliyun提供程序", "text": "Aliyun提供程序",
"path": "Blob-Storing-Aliyun.md" "path": "Blob-Storing-Aliyun.md"
}, },
{
"text": "Minio提供程序",
"path": "Blob-Storing-Minio.md"
},
{ {
"text": "创建自定义提供程序", "text": "创建自定义提供程序",
"path": "Blob-Storing-Custom-Provider.md" "path": "Blob-Storing-Custom-Provider.md"

13
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs

@ -1,5 +1,7 @@
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker; using Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -12,6 +14,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages
{ {
Configure<AbpLocalizationOptions>(options => Configure<AbpLocalizationOptions>(options =>
{ {
//BootstrapDatepicker
options.AddLanguagesMapOrUpdate(BootstrapDatepickerScriptContributor.PackageName, options.AddLanguagesMapOrUpdate(BootstrapDatepickerScriptContributor.PackageName,
new NameValue("zh-Hans", "zh-CN"), new NameValue("zh-Hans", "zh-CN"),
new NameValue("zh-Hant", "zh-TW")); new NameValue("zh-Hant", "zh-TW"));
@ -19,6 +22,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages
options.AddLanguageFilesMapOrUpdate(BootstrapDatepickerScriptContributor.PackageName, options.AddLanguageFilesMapOrUpdate(BootstrapDatepickerScriptContributor.PackageName,
new NameValue("zh-Hans", "zh-CN"), new NameValue("zh-Hans", "zh-CN"),
new NameValue("zh-Hant", "zh-TW")); new NameValue("zh-Hant", "zh-TW"));
//Timeago
options.AddLanguageFilesMapOrUpdate(TimeagoScriptContributor.PackageName,
new NameValue("zh-Hans", "zh-CN"),
new NameValue("zh-Hant", "zh-TW"));
//JQueryValidation
options.AddLanguageFilesMapOrUpdate(JQueryValidationScriptContributor.PackageName,
new NameValue("zh-Hans", "zh"),
new NameValue("zh-Hant", "zh_TW"));
}); });
} }
} }

21
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery;
using Volo.Abp.Localization; using Volo.Abp.Localization;
@ -19,26 +18,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker
public override void ConfigureDynamicResources(BundleConfigurationContext context) public override void ConfigureDynamicResources(BundleConfigurationContext context)
{ {
var cultureName = CultureInfo.CurrentUICulture.DateTimeFormat.Calendar.AlgorithmType == var fileName = context.LocalizationOptions.GetCurrentUICultureLanguageFilesMap(PackageName);
CalendarAlgorithmType.LunarCalendar
? "en"
: CultureInfo.CurrentUICulture.Name;
TryAddCultureFile(context, cultureName);
}
protected virtual bool TryAddCultureFile(BundleConfigurationContext context, string cultureName)
{
var fileName = context.LocalizationOptions.GetLanguageFilesMap(PackageName, cultureName);
var filePath = $"/libs/bootstrap-datepicker/locales/bootstrap-datepicker.{fileName}.min.js"; var filePath = $"/libs/bootstrap-datepicker/locales/bootstrap-datepicker.{fileName}.min.js";
if (context.FileProvider.GetFileInfo(filePath).Exists)
if (!context.FileProvider.GetFileInfo(filePath).Exists)
{ {
return false; context.Files.AddIfNotContains(filePath);
} }
context.Files.AddIfNotContains(filePath);
return true;
} }
} }
} }

40
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JQueryValidation/JQueryValidationScriptContributor.cs

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery;
using Volo.Abp.Localization; using Volo.Abp.Localization;
@ -10,8 +9,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation
[DependsOn(typeof(JQueryScriptContributor))] [DependsOn(typeof(JQueryScriptContributor))]
public class JQueryValidationScriptContributor : BundleContributor public class JQueryValidationScriptContributor : BundleContributor
{ {
public const string DefaultLocalizationFolder = "/libs/jquery-validation/localization/";
public const string PackageName = "jquery-validation"; public const string PackageName = "jquery-validation";
public override void ConfigureBundle(BundleConfigurationContext context) public override void ConfigureBundle(BundleConfigurationContext context)
@ -21,41 +18,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation
public override void ConfigureDynamicResources(BundleConfigurationContext context) public override void ConfigureDynamicResources(BundleConfigurationContext context)
{ {
//TODO: Can we optimize these points: var fileName = context.LocalizationOptions.GetCurrentUICultureLanguageFilesMap(PackageName);
// - Can we get rid of context.FileProvider.GetFileInfo call? var filePath = $"/libs/jquery-validation/localization/messages_{fileName}.js";
// - What if the same Contributor is used twice for a page. if (context.FileProvider.GetFileInfo(filePath).Exists)
// Duplication is prevented by the bundle manager, however the logic below will execute twice
var cultureName = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName.Replace('-', '_');
var fileName = context.LocalizationOptions.GetLanguageFilesMap(PackageName, cultureName);
if (TryAddCultureFile(context, fileName))
{
return;
}
if (!cultureName.Contains("_"))
{
return;
}
fileName = context.LocalizationOptions.GetLanguageFilesMap(PackageName,
cultureName.Substring(0, cultureName.IndexOf('_')));
TryAddCultureFile(context, fileName);
}
protected virtual bool TryAddCultureFile(BundleConfigurationContext context, string cultureName)
{
var filePath = DefaultLocalizationFolder + "messages_" + cultureName + ".js";
var fileInfo = context.FileProvider.GetFileInfo(filePath);
if (!fileInfo.Exists)
{ {
return false; context.Files.AddIfNotContains(filePath);
} }
context.Files.AddIfNotContains(filePath);
return true;
} }
} }
} }

18
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery;
using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago
@ -9,6 +9,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago
[DependsOn(typeof(JQueryScriptContributor))] [DependsOn(typeof(JQueryScriptContributor))]
public class TimeagoScriptContributor : BundleContributor public class TimeagoScriptContributor : BundleContributor
{ {
public const string PackageName = "jquery.timeago";
public override void ConfigureBundle(BundleConfigurationContext context) public override void ConfigureBundle(BundleConfigurationContext context)
{ {
context.Files.AddIfNotContains("/libs/timeago/jquery.timeago.js"); context.Files.AddIfNotContains("/libs/timeago/jquery.timeago.js");
@ -16,17 +18,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago
public override void ConfigureDynamicResources(BundleConfigurationContext context) public override void ConfigureDynamicResources(BundleConfigurationContext context)
{ {
var cultureName = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName; var fileName = context.LocalizationOptions.GetCurrentUICultureLanguageFilesMap(PackageName);
if (cultureName.StartsWith("en")) var filePath = $"/libs/timeago/locales/jquery.timeago.{fileName}.js";
{ if (context.FileProvider.GetFileInfo(filePath).Exists)
return;
}
var cultureFileName = $"/libs/timeago/locales/jquery.timeago.{cultureName}.js";
if (context.FileProvider.GetFileInfo(cultureFileName).Exists)
{ {
context.Files.Add(cultureFileName); context.Files.Add(filePath);
} }
} }
} }

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

@ -299,6 +299,13 @@
column.targets = i; column.targets = i;
} }
if (!column.render && column.dataFormat) {
var render = datatables.defaultRenderers[column.dataFormat];
if (render) {
column.render = render;
}
}
if (column.rowAction) { if (column.rowAction) {
customizeRowActionColumn(column); customizeRowActionColumn(column);
} }
@ -330,18 +337,23 @@
} }
}; };
var ISOStringToDateTimeLocaleString = function (format) {
return function(data) {
var date = luxon
.DateTime
.fromISO(data, {
locale: abp.localization.currentCulture.name
});
return format ? date.toLocaleString(format) : date.toLocaleString();
};
};
datatables.defaultRenderers['date'] = function (value) { datatables.defaultRenderers['date'] = function (value) {
return luxon return (ISOStringToDateTimeLocaleString())(value);
.DateTime
.fromISO(value, { locale: abp.localization.currentCulture.name })
.toLocaleString();
}; };
datatables.defaultRenderers['datetime'] = function (value) { datatables.defaultRenderers['datetime'] = function (value) {
return luxon return (ISOStringToDateTimeLocaleString(luxon.DateTime.DATETIME_SHORT))(value);
.DateTime
.fromISO(value, { locale: abp.localization.currentCulture.name })
.toLocaleString(luxon.DateTime.DATETIME_SHORT);
}; };
/************************************************************************ /************************************************************************

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -270,7 +270,7 @@ namespace Volo.Abp.AspNetCore.Mvc
return parameterInfo.Name; return parameterInfo.Name;
} }
return modelNameProvider.Name; return modelNameProvider.Name ?? parameterInfo.Name;
} }
private static string GetRootPath([NotNull] Type controllerType, [CanBeNull] ConventionalControllerSetting setting) private static string GetRootPath([NotNull] Type controllerType, [CanBeNull] ConventionalControllerSetting setting)

38
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs

@ -11,6 +11,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.DependencyInjection; using Volo.Abp.EntityFrameworkCore.DependencyInjection;
using Volo.Abp.Guids;
namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
{ {
@ -29,9 +30,12 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
private readonly IDbContextProvider<TDbContext> _dbContextProvider; private readonly IDbContextProvider<TDbContext> _dbContextProvider;
private readonly Lazy<AbpEntityOptions<TEntity>> _entityOptionsLazy; private readonly Lazy<AbpEntityOptions<TEntity>> _entityOptionsLazy;
protected virtual IGuidGenerator GuidGenerator { get; set; }
public EfCoreRepository(IDbContextProvider<TDbContext> dbContextProvider) public EfCoreRepository(IDbContextProvider<TDbContext> dbContextProvider)
{ {
_dbContextProvider = dbContextProvider; _dbContextProvider = dbContextProvider;
GuidGenerator = SimpleGuidGenerator.Instance;
_entityOptionsLazy = new Lazy<AbpEntityOptions<TEntity>>( _entityOptionsLazy = new Lazy<AbpEntityOptions<TEntity>>(
() => ServiceProvider () => ServiceProvider
@ -40,9 +44,11 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
.GetOrNull<TEntity>() ?? AbpEntityOptions<TEntity>.Empty .GetOrNull<TEntity>() ?? AbpEntityOptions<TEntity>.Empty
); );
} }
public override async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) public override async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{ {
CheckAndSetId(entity);
var savedEntity = DbSet.Add(entity).Entity; var savedEntity = DbSet.Add(entity).Entity;
if (autoSave) if (autoSave)
@ -66,7 +72,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
return updatedEntity; return updatedEntity;
} }
public override async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) public override async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{ {
DbSet.Remove(entity); DbSet.Remove(entity);
@ -110,7 +116,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
} }
public override async Task<TEntity> FindAsync( public override async Task<TEntity> FindAsync(
Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true, bool includeDetails = true,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
@ -188,16 +194,38 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
return query; return query;
} }
protected virtual void CheckAndSetId(TEntity entity)
{
if (entity is IEntity<Guid> entityWithGuidId)
{
TrySetGuidId(entityWithGuidId);
}
}
protected virtual void TrySetGuidId(IEntity<Guid> entity)
{
if (entity.Id != default)
{
return;
}
EntityHelper.TrySetId(
entity,
() => GuidGenerator.Create(),
true
);
}
} }
public class EfCoreRepository<TDbContext, TEntity, TKey> : EfCoreRepository<TDbContext, TEntity>, public class EfCoreRepository<TDbContext, TEntity, TKey> : EfCoreRepository<TDbContext, TEntity>,
IEfCoreRepository<TEntity, TKey>, IEfCoreRepository<TEntity, TKey>,
ISupportsExplicitLoading<TEntity, TKey> ISupportsExplicitLoading<TEntity, TKey>
where TDbContext : IEfCoreDbContext where TDbContext : IEfCoreDbContext
where TEntity : class, IEntity<TKey> where TEntity : class, IEntity<TKey>
{ {
public EfCoreRepository(IDbContextProvider<TDbContext> dbContextProvider) public EfCoreRepository(IDbContextProvider<TDbContext> dbContextProvider)
: base(dbContextProvider) : base(dbContextProvider)
{ {

11
framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
namespace Volo.Abp.Localization namespace Volo.Abp.Localization
@ -24,6 +25,11 @@ namespace Volo.Abp.Localization
: language; : language;
} }
public static string GetCurrentUICultureLanguagesMap(this AbpLocalizationOptions localizationOptions, string packageName)
{
return GetLanguagesMap(localizationOptions, packageName, CultureInfo.CurrentUICulture.Name);
}
public static AbpLocalizationOptions AddLanguageFilesMapOrUpdate(this AbpLocalizationOptions localizationOptions, public static AbpLocalizationOptions AddLanguageFilesMapOrUpdate(this AbpLocalizationOptions localizationOptions,
string packageName, params NameValue[] maps) string packageName, params NameValue[] maps)
{ {
@ -43,6 +49,11 @@ namespace Volo.Abp.Localization
: language; : language;
} }
public static string GetCurrentUICultureLanguageFilesMap(this AbpLocalizationOptions localizationOptions, string packageName)
{
return GetLanguageFilesMap(localizationOptions, packageName, CultureInfo.CurrentUICulture.Name);
}
private static void AddOrUpdate(IDictionary<string, List<NameValue>> maps, string packageName, NameValue value) private static void AddOrUpdate(IDictionary<string, List<NameValue>> maps, string packageName, NameValue value)
{ {
if (maps.TryGetValue(packageName, out var existMaps)) if (maps.TryGetValue(packageName, out var existMaps))

1
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs

@ -50,6 +50,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
LocalEventBus = NullLocalEventBus.Instance; LocalEventBus = NullLocalEventBus.Instance;
DistributedEventBus = NullDistributedEventBus.Instance; DistributedEventBus = NullDistributedEventBus.Instance;
EntityChangeEventHelper = NullEntityChangeEventHelper.Instance; EntityChangeEventHelper = NullEntityChangeEventHelper.Instance;
GuidGenerator = SimpleGuidGenerator.Instance;
} }
public override async Task<TEntity> InsertAsync( public override async Task<TEntity> InsertAsync(

10
framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs

@ -64,5 +64,15 @@ namespace Volo.Abp.MongoDB.Repositories
person.Phones.Count.ShouldBe(1); person.Phones.Count.ShouldBe(1);
person.Phones.Any(p => p.PersonId == person.Id && p.Number == "1234567890").ShouldBeTrue(); person.Phones.Any(p => p.PersonId == person.Id && p.Number == "1234567890").ShouldBeTrue();
} }
[Fact]
public async Task Insert_Should_Set_Guid_Id()
{
var person = new Person(Guid.Empty, "New Person", 35);
await PersonRepository.InsertAsync(person);
person.Id.ShouldNotBe(Guid.Empty);
}
} }
} }

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

@ -38,15 +38,12 @@
</label> </label>
</div> </div>
<abp-button type="submit" button-type="Primary" name="Action" value="Login" class="btn-block btn-lg mt-3">@L["Login"]</abp-button> <abp-button type="submit" button-type="Primary" name="Action" value="Login" class="btn-block btn-lg mt-3">@L["Login"]</abp-button>
@if (Model.ShowCancelButton)
{
<abp-button type="submit" button-type="Secondary" formnovalidate="formnovalidate" name="Action" value="Cancel" class="btn-block btn-lg mt-3">@L["Cancel"]</abp-button>
}
</form> </form>
</div> </div>
@if (Model.ShowCancelButton)
{
<div class="card-footer text-center border-0">
<abp-button type="button" button-type="Link" name="Action" value="Cancel" class="px-2 py-0">@L["Cancel"]</abp-button>
</div>
}
</div> </div>
} }

Loading…
Cancel
Save