diff --git a/docs/en/Blob-Storing-Minio.md b/docs/en/Blob-Storing-Minio.md new file mode 100644 index 0000000000..e7ec455716 --- /dev/null +++ b/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(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/` 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. diff --git a/docs/en/Blob-Storing.md b/docs/en/Blob-Storing.md index 2b49a896cd..444766b4bb 100644 --- a/docs/en/Blob-Storing.md +++ b/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. * [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/). +* [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. diff --git a/docs/en/Samples/Microservice-Demo.md b/docs/en/Samples/Microservice-Demo.md index 30059a9379..9b4c622c4e 100644 --- a/docs/en/Samples/Microservice-Demo.md +++ b/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+ * [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 the `samples\MicroserviceDemo\MicroserviceDemo.sln` in Visual Studio 2017 (15.9.0+). diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index eaeaad8346..8952e3c997 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -220,6 +220,10 @@ "text": "Aliyun Provider", "path": "Blob-Storing-Aliyun.md" }, + { + "text": "Minio Provider", + "path": "Blob-Storing-Minio.md" + }, { "text": "Create a Custom Provider", "path": "Blob-Storing-Custom-Provider.md" diff --git a/docs/zh-Hans/Blob-Storing-Minio.md b/docs/zh-Hans/Blob-Storing-Minio.md new file mode 100644 index 0000000000..f7c0b25771 --- /dev/null +++ b/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(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/` 字符串, +* 追加 BLOB 名称, + +## 其他服务 + +* `MinioBlobProvider` 是实现Minio BLOB存储提供程序的主要服务,如果你想要通过[依赖注入](Dependency-Injection.md)覆盖/替换它(不要替换 `IBlobProvider` 接口,而是替换 `MinioBlobProvider` 类). +* `IMinioBlobNameCalculator` 服务用于计算文件路径. 默认实现是 `DefaultMinioBlobNameCalculator`. 如果你想自定义文件路径计算,可以替换/覆盖它. diff --git a/docs/zh-Hans/Blob-Storing.md b/docs/zh-Hans/Blob-Storing.md index 43b2ebb96b..ba166d6aeb 100644 --- a/docs/zh-Hans/Blob-Storing.md +++ b/docs/zh-Hans/Blob-Storing.md @@ -19,6 +19,8 @@ ABP框架已经有以下存储提供程序的实现; * [File System](Blob-Storing-File-System.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/)中. +* [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框架. diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index 726ff8816c..732f6c08f4 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -214,6 +214,10 @@ "text": "Aliyun提供程序", "path": "Blob-Storing-Aliyun.md" }, + { + "text": "Minio提供程序", + "path": "Blob-Storing-Minio.md" + }, { "text": "创建自定义提供程序", "path": "Blob-Storing-Custom-Provider.md" diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs index a5ee47a753..93fa193bc7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs +++ b/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.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.Modularity; @@ -12,6 +14,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages { Configure(options => { + //BootstrapDatepicker options.AddLanguagesMapOrUpdate(BootstrapDatepickerScriptContributor.PackageName, new NameValue("zh-Hans", "zh-CN"), new NameValue("zh-Hant", "zh-TW")); @@ -19,6 +22,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages options.AddLanguageFilesMapOrUpdate(BootstrapDatepickerScriptContributor.PackageName, new NameValue("zh-Hans", "zh-CN"), 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")); }); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs index ca852972d8..751fb8c53e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs +++ b/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.Globalization; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; using Volo.Abp.Localization; @@ -19,26 +18,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker public override void ConfigureDynamicResources(BundleConfigurationContext context) { - var cultureName = CultureInfo.CurrentUICulture.DateTimeFormat.Calendar.AlgorithmType == - 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 fileName = context.LocalizationOptions.GetCurrentUICultureLanguageFilesMap(PackageName); 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; } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JQueryValidation/JQueryValidationScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JQueryValidation/JQueryValidationScriptContributor.cs index 586d8864cd..c5387b233c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JQueryValidation/JQueryValidationScriptContributor.cs +++ b/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.Globalization; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; using Volo.Abp.Localization; @@ -10,8 +9,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation [DependsOn(typeof(JQueryScriptContributor))] public class JQueryValidationScriptContributor : BundleContributor { - public const string DefaultLocalizationFolder = "/libs/jquery-validation/localization/"; - public const string PackageName = "jquery-validation"; public override void ConfigureBundle(BundleConfigurationContext context) @@ -21,41 +18,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation public override void ConfigureDynamicResources(BundleConfigurationContext context) { - //TODO: Can we optimize these points: - // - Can we get rid of context.FileProvider.GetFileInfo call? - // - What if the same Contributor is used twice for a page. - // 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) + var fileName = context.LocalizationOptions.GetCurrentUICultureLanguageFilesMap(PackageName); + var filePath = $"/libs/jquery-validation/localization/messages_{fileName}.js"; + if (context.FileProvider.GetFileInfo(filePath).Exists) { - return false; + context.Files.AddIfNotContains(filePath); } - - context.Files.AddIfNotContains(filePath); - return true; } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs index 9edbf065cb..56adbe5deb 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs +++ b/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.Globalization; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; +using Volo.Abp.Localization; using Volo.Abp.Modularity; namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago @@ -9,6 +9,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago [DependsOn(typeof(JQueryScriptContributor))] public class TimeagoScriptContributor : BundleContributor { + public const string PackageName = "jquery.timeago"; + public override void ConfigureBundle(BundleConfigurationContext context) { 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) { - var cultureName = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName; - if (cultureName.StartsWith("en")) - { - return; - } - - var cultureFileName = $"/libs/timeago/locales/jquery.timeago.{cultureName}.js"; - - if (context.FileProvider.GetFileInfo(cultureFileName).Exists) + var fileName = context.LocalizationOptions.GetCurrentUICultureLanguageFilesMap(PackageName); + var filePath = $"/libs/timeago/locales/jquery.timeago.{fileName}.js"; + if (context.FileProvider.GetFileInfo(filePath).Exists) { - context.Files.Add(cultureFileName); + context.Files.Add(filePath); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js index 824e376934..9a2052b267 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js +++ b/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; } + if (!column.render && column.dataFormat) { + var render = datatables.defaultRenderers[column.dataFormat]; + if (render) { + column.render = render; + } + } + if (column.rowAction) { 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) { - return luxon - .DateTime - .fromISO(value, { locale: abp.localization.currentCulture.name }) - .toLocaleString(); + return (ISOStringToDateTimeLocaleString())(value); }; datatables.defaultRenderers['datetime'] = function (value) { - return luxon - .DateTime - .fromISO(value, { locale: abp.localization.currentCulture.name }) - .toLocaleString(luxon.DateTime.DATETIME_SHORT); + return (ISOStringToDateTimeLocaleString(luxon.DateTime.DATETIME_SHORT))(value); }; /************************************************************************ diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/jquery/widget-manager.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/jquery/widget-manager.js index 0b746b5e37..e0fdf0bafa 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/jquery/widget-manager.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/jquery/widget-manager.js @@ -27,7 +27,7 @@ var getFilters = function ($widgetWrapperDiv) { var filters = {}; - + if (opts.filterForm) { opts.filterForm.each(function() { filters = $.extend(filters, opts.filterForm.serializeFormToObject()); @@ -47,7 +47,7 @@ }; var init = function () { - opts.wrapper.find('.abp-widget-wrapper').each(function () { + opts.wrapper.findWithSelf('.abp-widget-wrapper').each(function () { var $widgetWrapperDiv = $(this); var widgetName = $widgetWrapperDiv.attr('data-widget-name'); var widgetApiClass = abp.widgets[widgetName]; @@ -62,7 +62,7 @@ }; var refresh = function () { - opts.wrapper.find('.abp-widget-wrapper').each(function () { + opts.wrapper.findWithSelf('.abp-widget-wrapper').each(function () { var $widgetWrapperDiv = $(this); var refreshUrl = $widgetWrapperDiv.attr('data-refresh-url'); @@ -104,4 +104,4 @@ return publicApi; }; -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs index 1042ee4d08..f5ea41d765 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs +++ b/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 modelNameProvider.Name; + return modelNameProvider.Name ?? parameterInfo.Name; } private static string GetRootPath([NotNull] Type controllerType, [CanBeNull] ConventionalControllerSetting setting) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs index 378b92a14a..04238a9a45 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.AspNetCore.WebClientInfo; using Volo.Abp.Auditing; using Volo.Abp.DependencyInjection; @@ -35,14 +36,15 @@ namespace Volo.Abp.AspNetCore.Auditing context.AuditInfo.Url = BuildUrl(httpContext); } + var clientInfoProvider = context.ServiceProvider.GetRequiredService(); if (context.AuditInfo.ClientIpAddress == null) { - context.AuditInfo.ClientIpAddress = GetClientIpAddress(httpContext); + context.AuditInfo.ClientIpAddress = clientInfoProvider.ClientIpAddress; } if (context.AuditInfo.BrowserInfo == null) { - context.AuditInfo.BrowserInfo = GetBrowserInfo(httpContext); + context.AuditInfo.BrowserInfo = clientInfoProvider.BrowserInfo; } //TODO: context.AuditInfo.ClientName @@ -62,24 +64,6 @@ namespace Volo.Abp.AspNetCore.Auditing } } - protected virtual string GetBrowserInfo(HttpContext httpContext) - { - return httpContext.Request?.Headers?["User-Agent"]; - } - - protected virtual string GetClientIpAddress(HttpContext httpContext) - { - try - { - return httpContext.Connection?.RemoteIpAddress?.ToString(); - } - catch (Exception ex) - { - Logger.LogException(ex, LogLevel.Warning); - return null; - } - } - protected virtual string BuildUrl(HttpContext httpContext) { //TODO: Add options to include/exclude query, schema and host diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs new file mode 100644 index 0000000000..f0fc0aa347 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs @@ -0,0 +1,73 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.WebClientInfo; +using Volo.Abp.Clients; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SecurityLog; +using Volo.Abp.Timing; +using Volo.Abp.Tracing; +using Volo.Abp.Users; + +namespace Volo.Abp.AspNetCore.SecurityLog +{ + [Dependency(ReplaceServices = true)] + public class AspNetCoreSecurityLogManager : DefaultSecurityLogManager + { + protected ILogger Logger { get; } + protected IClock Clock { get; } + protected ICurrentUser CurrentUser { get; } + protected ICurrentTenant CurrentTenant { get; } + protected ICurrentClient CurrentClient { get; } + protected IHttpContextAccessor HttpContextAccessor { get; } + protected ICorrelationIdProvider CorrelationIdProvider { get; } + protected IWebClientInfoProvider WebClientInfoProvider { get; } + + public AspNetCoreSecurityLogManager( + IOptions securityLogOptions, + ISecurityLogStore securityLogStore, + ILogger logger, + IClock clock, + ICurrentUser currentUser, + ICurrentTenant currentTenant, + ICurrentClient currentClient, + IHttpContextAccessor httpContextAccessor, + ICorrelationIdProvider correlationIdProvider, + IWebClientInfoProvider webClientInfoProvider) + : base(securityLogOptions, securityLogStore) + { + Logger = logger; + Clock = clock; + CurrentUser = currentUser; + CurrentTenant = currentTenant; + CurrentClient = currentClient; + HttpContextAccessor = httpContextAccessor; + CorrelationIdProvider = correlationIdProvider; + WebClientInfoProvider = webClientInfoProvider; + } + + protected override async Task CreateAsync() + { + var securityLogInfo = await base.CreateAsync(); + + securityLogInfo.CreationTime = Clock.Now; + + securityLogInfo.TenantId = CurrentTenant.Id; + securityLogInfo.TenantName = CurrentTenant.Name; + + securityLogInfo.UserId = CurrentUser.Id; + securityLogInfo.UserName = CurrentUser.UserName; + + securityLogInfo.ClientId = CurrentClient.Id; + + securityLogInfo.CorrelationId = CorrelationIdProvider.Get(); + + securityLogInfo.ClientIpAddress = WebClientInfoProvider.ClientIpAddress; + securityLogInfo.BrowserInfo = WebClientInfoProvider.BrowserInfo; + + return securityLogInfo; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs new file mode 100644 index 0000000000..503771c938 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs @@ -0,0 +1,43 @@ +using System; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.WebClientInfo +{ + public class HttpContextWebClientInfoProvider : IWebClientInfoProvider, ITransientDependency + { + protected ILogger Logger { get; } + protected IHttpContextAccessor HttpContextAccessor { get; } + + public HttpContextWebClientInfoProvider( + ILogger logger, + IHttpContextAccessor httpContextAccessor) + { + Logger = logger; + HttpContextAccessor = httpContextAccessor; + } + + public string BrowserInfo => GetBrowserInfo(); + + public string ClientIpAddress => GetClientIpAddress(); + + protected virtual string GetBrowserInfo() + { + return HttpContextAccessor.HttpContext?.Request?.Headers?["User-Agent"]; + } + + protected virtual string GetClientIpAddress() + { + try + { + return HttpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString(); + } + catch (Exception ex) + { + Logger.LogException(ex, LogLevel.Warning); + return null; + } + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/IWebClientInfoProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/IWebClientInfoProvider.cs new file mode 100644 index 0000000000..3a15ac2f93 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/IWebClientInfoProvider.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.AspNetCore.WebClientInfo +{ + public interface IWebClientInfoProvider + { + string BrowserInfo { get; } + + string ClientIpAddress { get; } + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityCreatedEto.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityCreatedEto.cs index d39b69c857..c96b5cc366 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityCreatedEto.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityCreatedEto.cs @@ -1,11 +1,12 @@ using System; using Volo.Abp.EventBus; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Domain.Entities.Events.Distributed { [Serializable] [GenericEventName(Postfix = ".Created")] - public class EntityCreatedEto + public class EntityCreatedEto : IEventDataMayHaveTenantId { public TEntityEto Entity { get; set; } @@ -13,5 +14,17 @@ namespace Volo.Abp.Domain.Entities.Events.Distributed { Entity = entity; } + + public virtual bool IsMultiTenant(out Guid? tenantId) + { + if (Entity is IMultiTenant multiTenantEntity) + { + tenantId = multiTenantEntity.TenantId; + return true; + } + + tenantId = null; + return false; + } } } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityDeletedEto.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityDeletedEto.cs index 9cf930d7db..6f9594427a 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityDeletedEto.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityDeletedEto.cs @@ -1,11 +1,12 @@ using System; using Volo.Abp.EventBus; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Domain.Entities.Events.Distributed { [Serializable] [GenericEventName(Postfix = ".Deleted")] - public class EntityDeletedEto + public class EntityDeletedEto : IEventDataMayHaveTenantId { public TEntityEto Entity { get; set; } @@ -13,5 +14,17 @@ namespace Volo.Abp.Domain.Entities.Events.Distributed { Entity = entity; } + + public virtual bool IsMultiTenant(out Guid? tenantId) + { + if (Entity is IMultiTenant multiTenantEntity) + { + tenantId = multiTenantEntity.TenantId; + return true; + } + + tenantId = null; + return false; + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityUpdatedEto.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityUpdatedEto.cs index 654dd4243f..54b0454903 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityUpdatedEto.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityUpdatedEto.cs @@ -1,11 +1,12 @@ using System; using Volo.Abp.EventBus; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Domain.Entities.Events.Distributed { [Serializable] [GenericEventName(Postfix = ".Updated")] - public class EntityUpdatedEto + public class EntityUpdatedEto : IEventDataMayHaveTenantId { public TEntityEto Entity { get; set; } @@ -13,5 +14,17 @@ namespace Volo.Abp.Domain.Entities.Events.Distributed { Entity = entity; } + + public virtual bool IsMultiTenant(out Guid? tenantId) + { + if (Entity is IMultiTenant multiTenantEntity) + { + tenantId = multiTenantEntity.TenantId; + return true; + } + + tenantId = null; + return false; + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityEventData.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityEventData.cs index 698648ead4..d8ade9c01c 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityEventData.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityEventData.cs @@ -1,5 +1,6 @@ using System; using Volo.Abp.EventBus; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Domain.Entities.Events { @@ -8,7 +9,7 @@ namespace Volo.Abp.Domain.Entities.Events /// /// Entity type [Serializable] - public class EntityEventData : IEventDataWithInheritableGenericArgument + public class EntityEventData : IEventDataWithInheritableGenericArgument, IEventDataMayHaveTenantId { /// /// Related entity with this event. @@ -28,5 +29,17 @@ namespace Volo.Abp.Domain.Entities.Events { return new object[] { Entity }; } + + public virtual bool IsMultiTenant(out Guid? tenantId) + { + if (Entity is IMultiTenant multiTenantEntity) + { + tenantId = multiTenantEntity.TenantId; + return true; + } + + tenantId = null; + return false; + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index 9515c72b6e..29f3726704 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/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.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.DependencyInjection; +using Volo.Abp.Guids; namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore { @@ -29,9 +30,12 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore private readonly IDbContextProvider _dbContextProvider; private readonly Lazy> _entityOptionsLazy; + protected virtual IGuidGenerator GuidGenerator { get; set; } + public EfCoreRepository(IDbContextProvider dbContextProvider) { _dbContextProvider = dbContextProvider; + GuidGenerator = SimpleGuidGenerator.Instance; _entityOptionsLazy = new Lazy>( () => ServiceProvider @@ -40,9 +44,11 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore .GetOrNull() ?? AbpEntityOptions.Empty ); } - + public override async Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { + CheckAndSetId(entity); + var savedEntity = DbSet.Add(entity).Entity; if (autoSave) @@ -66,7 +72,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return updatedEntity; } - + public override async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { DbSet.Remove(entity); @@ -110,7 +116,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore } public override async Task FindAsync( - Expression> predicate, + Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) { @@ -188,16 +194,38 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return query; } + + protected virtual void CheckAndSetId(TEntity entity) + { + if (entity is IEntity entityWithGuidId) + { + TrySetGuidId(entityWithGuidId); + } + } + + protected virtual void TrySetGuidId(IEntity entity) + { + if (entity.Id != default) + { + return; + } + + EntityHelper.TrySetId( + entity, + () => GuidGenerator.Create(), + true + ); + } } - public class EfCoreRepository : EfCoreRepository, + public class EfCoreRepository : EfCoreRepository, IEfCoreRepository, ISupportsExplicitLoading where TDbContext : IEfCoreDbContext where TEntity : class, IEntity { - public EfCoreRepository(IDbContextProvider dbContextProvider) + public EfCoreRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) { diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventDataMayHaveTenantId.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventDataMayHaveTenantId.cs new file mode 100644 index 0000000000..72a8c753cd --- /dev/null +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventDataMayHaveTenantId.cs @@ -0,0 +1,28 @@ +using System; + +namespace Volo.Abp.EventBus +{ + /// + /// An event data object (or event transfer object) can implement this interface + /// to indicate that this event may be related to a tenant. + /// + /// If an event data class is always related to a tenant, then directly implement the + /// interface instead of this one. + /// + /// This interface is typically implemented by generic event handlers where the generic + /// parameter may implement or not. + /// + public interface IEventDataMayHaveTenantId + { + /// + /// Returns true if this event data has a Tenant Id information. + /// If so, it should set the our parameter. + /// Otherwise, the our parameter value should not be informative + /// (it will be null as expected, but doesn't indicate a tenant with null tenant id). + /// + /// + /// The tenant id that is set if this method returns true. + /// + bool IsMultiTenant(out Guid? tenantId); + } +} diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs index 36355027db..410e4684cc 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; namespace Volo.Abp.Localization @@ -24,6 +25,11 @@ namespace Volo.Abp.Localization : language; } + public static string GetCurrentUICultureLanguagesMap(this AbpLocalizationOptions localizationOptions, string packageName) + { + return GetLanguagesMap(localizationOptions, packageName, CultureInfo.CurrentUICulture.Name); + } + public static AbpLocalizationOptions AddLanguageFilesMapOrUpdate(this AbpLocalizationOptions localizationOptions, string packageName, params NameValue[] maps) { @@ -43,6 +49,11 @@ namespace Volo.Abp.Localization : language; } + public static string GetCurrentUICultureLanguageFilesMap(this AbpLocalizationOptions localizationOptions, string packageName) + { + return GetLanguageFilesMap(localizationOptions, packageName, CultureInfo.CurrentUICulture.Name); + } + private static void AddOrUpdate(IDictionary> maps, string packageName, NameValue value) { if (maps.TryGetValue(packageName, out var existMaps)) diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 132801b203..8676ac0f34 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/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; DistributedEventBus = NullDistributedEventBus.Instance; EntityChangeEventHelper = NullEntityChangeEventHelper.Instance; + GuidGenerator = SimpleGuidGenerator.Instance; } public override async Task InsertAsync( diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/AbpSecurityLogOptions.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/AbpSecurityLogOptions.cs new file mode 100644 index 0000000000..a1cc6406f4 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/AbpSecurityLogOptions.cs @@ -0,0 +1,21 @@ +namespace Volo.Abp.SecurityLog +{ + public class AbpSecurityLogOptions + { + /// + /// Default: true. + /// + public bool IsEnabled { get; set; } + + /// + /// The name of the application or service writing security log. + /// Default: null. + /// + public string ApplicationName { get; set; } + + public AbpSecurityLogOptions() + { + IsEnabled = true; + } + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs new file mode 100644 index 0000000000..f628958bc4 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.SecurityLog +{ + public class DefaultSecurityLogManager : ISecurityLogManager, ITransientDependency + { + protected AbpSecurityLogOptions SecurityLogOptions { get; } + + protected ISecurityLogStore SecurityLogStore { get; } + + public DefaultSecurityLogManager( + IOptions securityLogOptions, + ISecurityLogStore securityLogStore) + { + SecurityLogStore = securityLogStore; + SecurityLogOptions = securityLogOptions.Value; + } + + public async Task SaveAsync(Action saveAction = null) + { + if (!SecurityLogOptions.IsEnabled) + { + return; + } + + var securityLogInfo = await CreateAsync(); + saveAction?.Invoke(securityLogInfo); + await SecurityLogStore.SaveAsync(securityLogInfo); + } + + protected virtual Task CreateAsync() + { + return Task.FromResult(new SecurityLogInfo + { + ApplicationName = SecurityLogOptions.ApplicationName + }); + } + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs new file mode 100644 index 0000000000..f368489fb0 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs @@ -0,0 +1,10 @@ +using System; +using System.Threading.Tasks; + +namespace Volo.Abp.SecurityLog +{ + public interface ISecurityLogManager + { + Task SaveAsync(Action saveAction = null); + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogStore.cs new file mode 100644 index 0000000000..df2496f307 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogStore.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.SecurityLog +{ + public interface ISecurityLogStore + { + Task SaveAsync(SecurityLogInfo securityLogInfo); + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs new file mode 100644 index 0000000000..b187b5bfa2 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.SecurityLog +{ + [Serializable] + public class SecurityLogInfo + { + public string ApplicationName { get; set; } + + public string Identity { get; set; } + + public string Action { get; set; } + + public Dictionary ExtraProperties { get; } + + public Guid? UserId { get; set; } + + public string UserName { get; set; } + + public Guid? TenantId { get; set; } + + public string TenantName { get; set; } + + public string ClientId { get; set; } + + public string CorrelationId { get; set; } + + public string ClientIpAddress { get; set; } + + public string BrowserInfo { get; set; } + + public DateTime CreationTime { get; set; } + + public SecurityLogInfo() + { + ExtraProperties = new Dictionary(); + } + + public override string ToString() + { + return $"SECURITY LOG: [{ApplicationName} - {Identity} - {Action}]"; + } + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs new file mode 100644 index 0000000000..fe6496ef40 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.SecurityLog +{ + public class SimpleSecurityLogStore : ISecurityLogStore, ITransientDependency + { + public ILogger Logger { get; set; } + protected AbpSecurityLogOptions SecurityLogOptions { get; } + + public SimpleSecurityLogStore(ILogger logger, IOptions securityLogOptions) + { + Logger = logger; + SecurityLogOptions = securityLogOptions.Value; + } + + public Task SaveAsync(SecurityLogInfo securityLogInfo) + { + if (!SecurityLogOptions.IsEnabled) + { + return Task.CompletedTask; + } + + Logger.LogInformation(securityLogInfo.ToString()); + return Task.CompletedTask; + } + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs index 09b1551e3d..a730fa4ecc 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs +++ b/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.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); + } } } diff --git a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs index b71a0a214a..a1ce5c56aa 100644 --- a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs +++ b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs @@ -1,4 +1,5 @@ using Volo.Abp.Modularity; +using Volo.Abp.SecurityLog; namespace Volo.Abp.Security { @@ -8,6 +9,12 @@ namespace Volo.Abp.Security )] public class AbpSecurityTestModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(x => + { + x.ApplicationName = "AbpSecurityTest"; + }); + } } } diff --git a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/SecurityLog/SecurityLogManager_Tests.cs b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/SecurityLog/SecurityLogManager_Tests.cs new file mode 100644 index 0000000000..94fb6bccda --- /dev/null +++ b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/SecurityLog/SecurityLogManager_Tests.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; +using Volo.Abp.SecurityLog; +using Volo.Abp.Testing; +using Xunit; + +namespace Volo.Abp.Security.SecurityLog +{ + + public class SecurityLogManager_Tests : AbpIntegratedTest + { + private readonly ISecurityLogManager _securityLogManager; + + private ISecurityLogStore _auditingStore; + + public SecurityLogManager_Tests() + { + _securityLogManager = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + _auditingStore = Substitute.For(); + services.AddSingleton(_auditingStore); + } + + [Fact] + public async Task SaveAsync() + { + await _securityLogManager.SaveAsync(securityLog => + { + securityLog.Identity = "Test"; + securityLog.Action = "Test-Action"; + securityLog.UserName = "Test-User"; + }); + + await _auditingStore.Received().SaveAsync(Arg.Is(log => + log.ApplicationName == "AbpSecurityTest" && + log.Identity == "Test" && + log.Action == "Test-Action" && + log.UserName == "Test-User")); + } + } +} diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs index 69986a45e9..5afe312a6e 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs @@ -14,7 +14,10 @@ using System.Security.Principal; using System.Threading.Tasks; using Volo.Abp.Account.Settings; using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; +using Volo.Abp.Identity.AspNetCore; using Volo.Abp.MultiTenancy; +using Volo.Abp.SecurityLog; using Volo.Abp.Settings; using Volo.Abp.Uow; @@ -129,6 +132,13 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = result.ToIdentitySecurityLogAction(), + UserName = LoginInput.UserNameOrEmailAddress + }); + if (result.RequiresTwoFactor) { return RedirectToPage("./SendSecurityCode", new diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs index 43857cc111..b25b34799d 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; namespace Volo.Abp.Account.Web.Pages.Account { @@ -19,6 +20,12 @@ namespace Volo.Abp.Account.Web.Pages.Account public override async Task OnGetAsync() { + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = IdentitySecurityLogActionConsts.Logout + }); + await SignInManager.SignOutAsync(); var logoutId = Request.Query["logoutId"].ToString(); diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs index 64fbdd40d1..aa22882701 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs @@ -6,7 +6,10 @@ using Volo.Abp.Account.Localization; using Volo.Abp.Account.Settings; using Volo.Abp.Account.Web.Areas.Account.Controllers.Models; using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.EventBus.Local; using Volo.Abp.Identity; +using Volo.Abp.Identity.AspNetCore; +using Volo.Abp.SecurityLog; using Volo.Abp.Settings; using Volo.Abp.Validation; using SignInResult = Microsoft.AspNetCore.Identity.SignInResult; @@ -26,13 +29,21 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers protected IdentityUserManager UserManager { get; } protected ISettingProvider SettingProvider { get; } - public AccountController(SignInManager signInManager, IdentityUserManager userManager, ISettingProvider settingProvider) + protected ILocalEventBus LocalEventBus { get; } + + public AccountController( + SignInManager signInManager, + IdentityUserManager userManager, + ISettingProvider settingProvider, + ISecurityLogManager securityLogManager, + ILocalEventBus localEventBus) { LocalizationResource = typeof(AccountResource); SignInManager = signInManager; UserManager = userManager; SettingProvider = settingProvider; + LocalEventBus = localEventBus; } [HttpPost] @@ -44,19 +55,33 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers ValidateLoginInfo(login); await ReplaceEmailToUsernameOfInputIfNeeds(login); - - return GetAbpLoginResult(await SignInManager.PasswordSignInAsync( + var signInResult = await SignInManager.PasswordSignInAsync( login.UserNameOrEmailAddress, login.Password, login.RememberMe, true - )); + ); + + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = signInResult.ToIdentitySecurityLogAction(), + UserName = login.UserNameOrEmailAddress + }); + + return GetAbpLoginResult(signInResult); } [HttpGet] [Route("logout")] public virtual async Task Logout() { + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = IdentitySecurityLogActionConsts.Logout + }); + await SignInManager.SignOutAsync(); } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs index 41bdd93647..e645c9c9cf 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Volo.Abp.Account.Localization; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.EventBus.Local; using Volo.Abp.Identity; using IdentityUser = Volo.Abp.Identity.IdentityUser; @@ -15,6 +15,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { public SignInManager SignInManager { get; set; } public IdentityUserManager UserManager { get; set; } + public ILocalEventBus LocalEventBus { get; set; } protected AccountPageModel() { diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml index 656f40850f..3bace4850b 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml @@ -38,15 +38,12 @@ @L["Login"] + @if (Model.ShowCancelButton) + { + @L["Cancel"] + } - - @if (Model.ShowCancelButton) - { - - } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index 8052b23cd9..05946182db 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -13,11 +13,12 @@ using System.Threading.Tasks; using Volo.Abp.Account.Settings; using Volo.Abp.Auditing; using Volo.Abp.Identity; +using Volo.Abp.Identity.AspNetCore; using Volo.Abp.Security.Claims; using Volo.Abp.Settings; -using Volo.Abp.Uow; using Volo.Abp.Validation; using IdentityUser = Volo.Abp.Identity.IdentityUser; +using SignInResult = Microsoft.AspNetCore.Identity.SignInResult; namespace Volo.Abp.Account.Web.Pages.Account { @@ -97,6 +98,13 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = result.ToIdentitySecurityLogAction(), + UserName = LoginInput.UserNameOrEmailAddress + }); + if (result.RequiresTwoFactor) { return RedirectToPage("./SendSecurityCode", new @@ -184,6 +192,15 @@ namespace Volo.Abp.Account.Web.Pages.Account bypassTwoFactor: true ); + if (!result.Succeeded) + { + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, + Action = "Login" + result + }); + } + if (result.IsLockedOut) { throw new UserFriendlyException("Cannot proceed because user is locked out!"); @@ -206,6 +223,14 @@ namespace Volo.Abp.Account.Web.Pages.Account var user = await CreateExternalUserAsync(info); await SignInManager.SignInAsync(user, false); + + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, + Action = result.ToIdentitySecurityLogAction(), + UserName = user.Name + }); + return RedirectSafely(returnUrl, returnUrlHash); } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs index 8cb2c2bc1e..fe7361e4ce 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Identity; namespace Volo.Abp.Account.Web.Pages.Account { @@ -15,6 +16,12 @@ namespace Volo.Abp.Account.Web.Pages.Account public virtual async Task OnGetAsync() { + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = IdentitySecurityLogActionConsts.Logout + }); + await SignInManager.SignOutAsync(); if (ReturnUrl != null) { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/Default.cshtml index 1d1c4e7306..3927ac3fdb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/Default.cshtml @@ -1,6 +1,6 @@ @model Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection.ReactionSelectionViewModel -
+
Pick a reaction: @foreach (var reaction in Model.Reactions) { @@ -9,7 +9,7 @@ }
-
+
Current reactions: @foreach (var reaction in Model.Reactions.Where(r => r.Count > 0)) { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionSelectionViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionSelectionViewComponent.cs index 45ae31c3b1..efb4db779e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionSelectionViewComponent.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionSelectionViewComponent.cs @@ -8,6 +8,7 @@ using Volo.CmsKit.Reactions; namespace Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection { + [ViewComponent(Name = "CmsReactionSelection")] [Widget( ScriptTypes = new[] {typeof(ReactionSelectionScriptBundleContributor)}, StyleTypes = new[] {typeof(ReactionSelectionStyleBundleContributor)} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.js b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.js index 50daa6f162..c7b31b1e1b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.js +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.js @@ -1,25 +1,46 @@ -(function () { +(function ($) { $(document).ready(function () { - function initReactionSelection() { - var $wrapper = $(this); - var $availableReactions = $wrapper.find('.cms-reaction-selection-available-reactions'); + abp.widgets.CmsReactionSelection = function ($widget) { - $wrapper.find('.cms-reaction-icon').each(function () { - var $icon = $(this); - $icon.click(function () { - var methodName = $icon.hasClass('cms-reaction-icon-selected') ? 'delete' : 'create'; - volo.cmsKit.reactions.reactionPublic[methodName]({ - entityType: $wrapper.attr('data-entity-type'), - entityId: $wrapper.attr('data-entity-id'), - reactionName: $icon.attr('data-name') - }).then(function () { - location.reload(); //TODO: JUST TESTING !!!!!!!! + function getFilters() { + return {}; + } + + function refresh(filters) { + location.reload(); //TODO: JUST TESTING !!!!!!!! + } + + function init(filters) { + var $wrapper = $widget.find('.cms-reaction-selection'); + $widget.find('.cms-reaction-icon').each(function () { + var $icon = $(this); + $icon.click(function () { + var methodName = $icon.hasClass('cms-reaction-icon-selected') ? 'delete' : 'create'; + volo.cmsKit.reactions.reactionPublic[methodName]({ + entityType: $wrapper.attr('data-entity-type'), + entityId: $wrapper.attr('data-entity-id'), + reactionName: $icon.attr('data-name') + }).then(function () { + refresh(); + }); }); }); + } + + return { + init: init, + refresh: refresh, + getFilters : getFilters + }; + }; + + $('.abp-widget-wrapper[data-widget-name="CmsReactionSelection"]').each(function () { + var widgetManager = new abp.WidgetManager({ + wrapper: $(this), }); - } - $('.cms-reaction-selection').each(initReactionSelection); + widgetManager.init(); + }); }); -})(); +})(jQuery); diff --git a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/SignInResultExtensions.cs b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/SignInResultExtensions.cs new file mode 100644 index 0000000000..39e3ae92fc --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/SignInResultExtensions.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Identity; + +namespace Volo.Abp.Identity.AspNetCore +{ + public static class SignInResultExtensions + { + public static string ToIdentitySecurityLogAction(this SignInResult result) + { + if (result.Succeeded) + { + return IdentitySecurityLogActionConsts.LoginSucceeded; + } + + if (result.IsLockedOut) + { + return IdentitySecurityLogActionConsts.LoginLockedout; + } + + if (result.RequiresTwoFactor) + { + return IdentitySecurityLogActionConsts.LoginRequiresTwoFactor; + } + + if (result.IsNotAllowed) + { + return IdentitySecurityLogActionConsts.LoginNotAllowed; + } + + if (!result.Succeeded) + { + return IdentitySecurityLogActionConsts.LoginFailed; + } + + return IdentitySecurityLogActionConsts.LoginFailed; + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogActionConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogActionConsts.cs new file mode 100644 index 0000000000..ea5276e673 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogActionConsts.cs @@ -0,0 +1,33 @@ +namespace Volo.Abp.Identity +{ + public class IdentitySecurityLogActionConsts + { + public static string LoginSucceeded { get; set; } = "LoginSucceeded"; + + public static string LoginLockedout { get; set; } = "LoginLockedout"; + + public static string LoginNotAllowed { get; set; } = "LoginNotAllowed"; + + public static string LoginRequiresTwoFactor { get; set; } = "LoginRequiresTwoFactor"; + + public static string LoginFailed { get; set; } = "LoginFailed"; + + public static string LoginInvalidUserName { get; set; } = "LoginInvalidUserName"; + + public static string LoginInvalidUserNameOrPassword { get; set; } = "LoginInvalidUserNameOrPassword"; + + public static string Logout { get; set; } = "Logout"; + + public static string ChangeUserName { get; set; } = "ChangeUserName"; + + public static string ChangeEmail { get; set; } = "ChangeEmail"; + + public static string ChangePhoneNumber { get; set; } = "ChangePhoneNumber"; + + public static string ChangePassword { get; set; } = "ChangePassword"; + + public static string TwoFactorEnabled { get; set; } = "TwoFactorEnabled"; + + public static string TwoFactorDisabled { get; set; } = "TwoFactorDisabled"; + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogConsts.cs new file mode 100644 index 0000000000..43b2dd25fb --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogConsts.cs @@ -0,0 +1,52 @@ +namespace Volo.Abp.Identity +{ + public class IdentitySecurityLogConsts + { + /// + /// Default value: 96 + /// + public static int MaxApplicationNameLength { get; set; } = 96; + + /// + /// Default value: 96 + /// + public static int MaxIdentityLength { get; set; } = 96; + + /// + /// Default value: 96 + /// + public static int MaxActionLength { get; set; } = 96; + + + /// + /// Default value: 256 + /// + public static int MaxUserNameLength { get; set; } = 256; + + /// + /// Default value: 64 + /// + public static int MaxTenantNameLength { get; set; } = 64; + + /// + /// Default value: 64 + /// + public static int MaxClientIpAddressLength { get; set; } = 64; + + /// + /// Default value: 64 + /// + public static int MaxClientIdLength { get; set; } = 64; + + /// + /// Default value: 64 + /// + public static int MaxCorrelationIdLength { get; set; } = 64; + + /// + /// Default value: 512 + /// + public static int MaxBrowserInfoLength { get; set; } = 512; + + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogIdentityConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogIdentityConsts.cs new file mode 100644 index 0000000000..5616dfb4e6 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogIdentityConsts.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.Identity +{ + public static class IdentitySecurityLogIdentityConsts + { + public static string Identity { get; set; } = "Identity"; + + public static string IdentityExternal { get; set; } = "IdentityExternal"; + + public static string IdentityTwoFactor { get; set; } = "IdentityTwoFactor"; + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs index 58349e8b69..0ef3582af1 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; using Microsoft.Extensions.Localization; using Volo.Abp.Identity; +using Volo.Abp.Localization; using Volo.Abp.Text.Formatting; namespace Microsoft.AspNetCore.Identity @@ -48,12 +49,15 @@ namespace Microsoft.AspNetCore.Identity if (!localizedString.ResourceNotFound) { - var englishLocalizedString = localizer.WithCulture(CultureInfo.GetCultureInfo("en"))[key]; - if (!englishLocalizedString.ResourceNotFound) + using (CultureHelper.Use(CultureInfo.GetCultureInfo("en"))) { - if (FormattedStringValueExtracter.IsMatch(error.Description, englishLocalizedString.Value, out var values)) + var englishLocalizedString = localizer[key]; + if (!englishLocalizedString.ResourceNotFound) { - return string.Format(localizedString.Value, values.Cast().ToArray()); + if (FormattedStringValueExtracter.IsMatch(error.Description, englishLocalizedString.Value, out var values)) + { + return string.Format(localizedString.Value, values.Cast().ToArray()); + } } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs new file mode 100644 index 0000000000..f68f289b4f --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.Identity +{ + public interface IIdentitySecurityLogRepository : IBasicRepository + { + Task> GetListAsync( + string sorting = null, + int maxResultCount = 50, + int skipCount = 0, + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + Guid? userId = null, + string userName = null, + string clientId = null, + string correlationId = null, + bool includeDetails = false, + CancellationToken cancellationToken = default); + + Task GetCountAsync( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + Guid? userId = null, + string userName = null, + string clientId = null, + string correlationId = null, + CancellationToken cancellationToken = default); + + Task GetByUserIdAsync( + Guid id, + Guid userId, + bool includeDetails = false, + CancellationToken cancellationToken = default); + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLog.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLog.cs new file mode 100644 index 0000000000..b720f667f0 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLog.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SecurityLog; + +namespace Volo.Abp.Identity +{ + public class IdentitySecurityLog : AggregateRoot, IMultiTenant + { + public Guid? TenantId { get; protected set; } + + public string ApplicationName { get; protected set; } + + public string Identity { get; protected set; } + + public string Action { get; protected set; } + + public Guid? UserId { get; protected set; } + + public string UserName { get; protected set; } + + public string TenantName { get; protected set; } + + public string ClientId { get; protected set; } + + public string CorrelationId { get; protected set; } + + public string ClientIpAddress { get; protected set; } + + public string BrowserInfo { get; protected set; } + + public DateTime CreationTime { get; protected set; } + + protected IdentitySecurityLog() + { + ExtraProperties = new Dictionary(); + } + + public IdentitySecurityLog(IGuidGenerator guidGenerator, SecurityLogInfo securityLogInfo) + { + Id = guidGenerator.Create(); + TenantId = securityLogInfo.TenantId; + TenantName = securityLogInfo.TenantName.Truncate(IdentitySecurityLogConsts.MaxTenantNameLength); + + ApplicationName = securityLogInfo.ApplicationName.Truncate(IdentitySecurityLogConsts.MaxApplicationNameLength); + Identity = securityLogInfo.Identity.Truncate(IdentitySecurityLogConsts.MaxIdentityLength); + Action = securityLogInfo.Action.Truncate(IdentitySecurityLogConsts.MaxActionLength); + + UserId = securityLogInfo.UserId; + UserName = securityLogInfo.UserName.Truncate(IdentitySecurityLogConsts.MaxUserNameLength); + + CreationTime = securityLogInfo.CreationTime; + + ClientIpAddress = securityLogInfo.ClientIpAddress.Truncate(IdentitySecurityLogConsts.MaxClientIpAddressLength); + ClientId = securityLogInfo.ClientId.Truncate(IdentitySecurityLogConsts.MaxClientIdLength); + CorrelationId = securityLogInfo.CorrelationId.Truncate(IdentitySecurityLogConsts.MaxCorrelationIdLength); + BrowserInfo = securityLogInfo.BrowserInfo.Truncate(IdentitySecurityLogConsts.MaxBrowserInfoLength); + + ExtraProperties = securityLogInfo.ExtraProperties; + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs new file mode 100644 index 0000000000..faac2d5033 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Identity +{ + public class IdentitySecurityLogEvent : IMultiTenant + { + public Guid? TenantId { get; set; } + + public string Identity { get; set; } + + public string Action { get; set; } + + public string UserName { get; set; } + + public string ClientId { get; set; } + + public Dictionary ExtraProperties { get; } + + public IdentitySecurityLogEvent() + { + ExtraProperties = new Dictionary(); + } + + public virtual IdentitySecurityLogEvent WithProperty(string key, object value) + { + ExtraProperties[key] = value; + return this; + } + + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs new file mode 100644 index 0000000000..5000d4d288 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs @@ -0,0 +1,86 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; +using Volo.Abp.Security.Claims; +using Volo.Abp.SecurityLog; +using Volo.Abp.Uow; +using Volo.Abp.Users; + +namespace Volo.Abp.Identity +{ + public class IdentitySecurityLogHandler : ILocalEventHandler, ITransientDependency + { + protected ISecurityLogManager SecurityLogManager { get; } + protected IdentityUserManager UserManager { get; } + protected ICurrentPrincipalAccessor CurrentPrincipalAccessor { get; } + protected IUserClaimsPrincipalFactory UserClaimsPrincipalFactory { get; } + protected ICurrentUser CurrentUser { get; } + + public IdentitySecurityLogHandler( + ISecurityLogManager securityLogManager, + IdentityUserManager userManager, + ICurrentPrincipalAccessor currentPrincipalAccessor, + IUserClaimsPrincipalFactory userClaimsPrincipalFactory, + ICurrentUser currentUser) + { + SecurityLogManager = securityLogManager; + UserManager = userManager; + CurrentPrincipalAccessor = currentPrincipalAccessor; + UserClaimsPrincipalFactory = userClaimsPrincipalFactory; + CurrentUser = currentUser; + } + + public async Task HandleEventAsync(IdentitySecurityLogEvent eventData) + { + Action securityLogAction = securityLog => + { + securityLog.Identity = eventData.Identity; + securityLog.Action = eventData.Action; + + if (securityLog.UserName.IsNullOrWhiteSpace()) + { + securityLog.UserName = eventData.UserName; + } + + if (securityLog.ClientId.IsNullOrWhiteSpace()) + { + securityLog.ClientId = eventData.ClientId; + } + + foreach (var property in eventData.ExtraProperties) + { + securityLog.ExtraProperties[property.Key] = property.Value; + } + }; + + if (CurrentUser.IsAuthenticated) + { + await SecurityLogManager.SaveAsync(securityLogAction); + } + else + { + if (eventData.UserName.IsNullOrWhiteSpace()) + { + await SecurityLogManager.SaveAsync(securityLogAction); + } + else + { + var user = await UserManager.FindByNameAsync(eventData.UserName); + if (user != null) + { + using (CurrentPrincipalAccessor.Change(await UserClaimsPrincipalFactory.CreateAsync(user))) + { + await SecurityLogManager.SaveAsync(securityLogAction); + } + } + else + { + await SecurityLogManager.SaveAsync(securityLogAction); + } + } + } + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs new file mode 100644 index 0000000000..17e3c20794 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Volo.Abp.SecurityLog; +using Volo.Abp.Uow; + +namespace Volo.Abp.Identity +{ + [Dependency(ReplaceServices = true)] + public class IdentitySecurityLogStore : ISecurityLogStore, ITransientDependency + { + public ILogger Logger { get; set; } + + protected AbpSecurityLogOptions SecurityLogOptions { get; } + protected IIdentitySecurityLogRepository IdentitySecurityLogRepository { get; } + protected IGuidGenerator GuidGenerator { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } + + public IdentitySecurityLogStore( + ILogger logger, + IOptions securityLogOptions, + IIdentitySecurityLogRepository identitySecurityLogRepository, + IGuidGenerator guidGenerator, + IUnitOfWorkManager unitOfWorkManager) + { + Logger = logger; + SecurityLogOptions = securityLogOptions.Value; + IdentitySecurityLogRepository = identitySecurityLogRepository; + GuidGenerator = guidGenerator; + UnitOfWorkManager = unitOfWorkManager; + } + + public async Task SaveAsync(SecurityLogInfo securityLogInfo) + { + if (!SecurityLogOptions.IsEnabled) + { + return; + } + + using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) + { + await IdentitySecurityLogRepository.InsertAsync(new IdentitySecurityLog(GuidGenerator, securityLogInfo)); + await uow.CompleteAsync(); + } + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs new file mode 100644 index 0000000000..137341a25e --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Volo.Abp.Identity.EntityFrameworkCore +{ + public class EFCoreIdentitySecurityLogRepository : EfCoreRepository, IIdentitySecurityLogRepository + { + public EFCoreIdentitySecurityLogRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + + } + + public async Task> GetListAsync( + string sorting = null, + int maxResultCount = 50, + int skipCount = 0, + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + Guid? userId = null, + string userName = null, + string clientId = null, + string correlationId = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userId, + userName, + clientId, + correlationId + ); + + return await query.OrderBy(sorting ?? nameof(IdentitySecurityLog.CreationTime) + " desc") + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async Task GetCountAsync( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + Guid? userId = null, + string userName = null, + string clientId = null, + string correlationId = null, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userId, + userName, + clientId, + correlationId + ); + + return await query.LongCountAsync(GetCancellationToken(cancellationToken)); + } + + public async Task GetByUserIdAsync(Guid id, Guid userId, bool includeDetails = false, CancellationToken cancellationToken = default) + { + return await DbSet.FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, GetCancellationToken(cancellationToken)); + } + + protected virtual IQueryable GetListQuery( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + Guid? userId = null, + string userName = null, + string clientId = null, + string correlationId = null) + { + return DbSet.AsNoTracking() + .WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime) + .WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime >= endTime) + .WhereIf(!applicationName.IsNullOrWhiteSpace(), securityLog => securityLog.ApplicationName == applicationName) + .WhereIf(!identity.IsNullOrWhiteSpace(), securityLog => securityLog.Identity == identity) + .WhereIf(!action.IsNullOrWhiteSpace(), securityLog => securityLog.Action == action) + .WhereIf(userId.HasValue, securityLog => securityLog.UserId == userId) + .WhereIf(!userName.IsNullOrWhiteSpace(), securityLog => securityLog.UserName == userName) + .WhereIf(!clientId.IsNullOrWhiteSpace(), securityLog => securityLog.ClientId == clientId) + .WhereIf(!correlationId.IsNullOrWhiteSpace(), securityLog => securityLog.CorrelationId == correlationId); + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs index f27c9b534a..48da4daf87 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.SecurityLog; namespace Volo.Abp.Identity.EntityFrameworkCore { @@ -14,5 +15,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore DbSet ClaimTypes { get; set; } DbSet OrganizationUnits { get; set; } + + DbSet IdentitySecurityLogs { get; set; } } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs index 811280de7b..16679429b8 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs @@ -18,6 +18,8 @@ namespace Volo.Abp.Identity.EntityFrameworkCore public DbSet OrganizationUnits { get; set; } + public DbSet IdentitySecurityLogs { get; set; } + public IdentityDbContext(DbContextOptions options) : base(options) { @@ -31,4 +33,4 @@ namespace Volo.Abp.Identity.EntityFrameworkCore builder.ConfigureIdentity(); } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs index 000a2a8f00..373abbe804 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs @@ -204,6 +204,32 @@ namespace Volo.Abp.Identity.EntityFrameworkCore b.HasIndex(ou => new {ou.UserId, ou.OrganizationUnitId}); }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "SecurityLogs", options.Schema); + + b.ConfigureByConvention(); + + b.Property(x => x.TenantName).HasMaxLength(IdentitySecurityLogConsts.MaxTenantNameLength); + + b.Property(x => x.ApplicationName).HasMaxLength(IdentitySecurityLogConsts.MaxApplicationNameLength); + b.Property(x => x.Identity).HasMaxLength(IdentitySecurityLogConsts.MaxIdentityLength); + b.Property(x => x.Action).HasMaxLength(IdentitySecurityLogConsts.MaxActionLength); + + b.Property(x => x.UserName).HasMaxLength(IdentitySecurityLogConsts.MaxUserNameLength); + + b.Property(x => x.ClientIpAddress).HasMaxLength(IdentitySecurityLogConsts.MaxClientIpAddressLength); + b.Property(x => x.ClientId).HasMaxLength(IdentitySecurityLogConsts.MaxClientIdLength); + b.Property(x => x.CorrelationId).HasMaxLength(IdentitySecurityLogConsts.MaxCorrelationIdLength); + b.Property(x => x.BrowserInfo).HasMaxLength(IdentitySecurityLogConsts.MaxBrowserInfoLength); + + b.HasIndex(x => new { x.TenantId, x.ApplicationName }); + b.HasIndex(x => new { x.TenantId, x.Identity }); + b.HasIndex(x => new { x.TenantId, x.Action }); + b.HasIndex(x => new { x.TenantId, x.UserId }); + }); + } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs index 3240ce1454..19c3316b88 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs @@ -15,6 +15,8 @@ namespace Volo.Abp.Identity.MongoDB public IMongoCollection OrganizationUnits => Collection(); + public IMongoCollection IdentitySecurityLogs => Collection(); + protected override void CreateModel(IMongoModelBuilder modelBuilder) { base.CreateModel(modelBuilder); @@ -22,4 +24,4 @@ namespace Volo.Abp.Identity.MongoDB modelBuilder.ConfigureIdentity(); } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs index bc303e0eb5..89aeddeb92 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs @@ -36,6 +36,11 @@ namespace Volo.Abp.Identity.MongoDB { b.CollectionName = options.CollectionPrefix + "OrganizationUnits"; }); + + builder.Entity(b => + { + b.CollectionName = options.CollectionPrefix + "SecurityLogs"; + }); } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs index 268c718b12..3ceab94e23 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs @@ -18,6 +18,7 @@ namespace Volo.Abp.Identity.MongoDB options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs index c903c5d96d..54819ffa19 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs @@ -14,5 +14,7 @@ namespace Volo.Abp.Identity.MongoDB IMongoCollection ClaimTypes { get; } IMongoCollection OrganizationUnits { get; } + + IMongoCollection IdentitySecurityLogs { get; } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs new file mode 100644 index 0000000000..4336abaaae --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.Identity.MongoDB +{ + public class MongoIdentitySecurityLogRepository : + MongoDbRepository, IIdentitySecurityLogRepository + { + public MongoIdentitySecurityLogRepository(IMongoDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task> GetListAsync( + string sorting = null, + int maxResultCount = 50, + int skipCount = 0, + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + Guid? userId = null, + string userName = null, + string clientId = null, + string correlationId = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userId, + userName, + clientId, + correlationId + ); + + return await query.OrderBy(sorting ?? nameof(IdentitySecurityLog.CreationTime) + " desc") + .As>() + .PageBy>(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async Task GetCountAsync( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + Guid? userId = null, + string userName = null, + string clientId = null, + string correlationId = null, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userId, + userName, + clientId, + correlationId + ); + + return await query.As>() + .LongCountAsync(GetCancellationToken(cancellationToken)); + } + + + public async Task GetByUserIdAsync(Guid id, Guid userId, bool includeDetails = false, + CancellationToken cancellationToken = default) + { + return await GetMongoQueryable().FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, + GetCancellationToken(cancellationToken)); + } + + protected virtual IQueryable GetListQuery( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + Guid? userId = null, + string userName = null, + string clientId = null, + string correlationId = null) + { + return GetMongoQueryable() + .WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime) + .WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime >= endTime) + .WhereIf(!applicationName.IsNullOrWhiteSpace(), + securityLog => securityLog.ApplicationName == applicationName) + .WhereIf(!identity.IsNullOrWhiteSpace(), securityLog => securityLog.Identity == identity) + .WhereIf(!action.IsNullOrWhiteSpace(), securityLog => securityLog.Action == action) + .WhereIf(userId.HasValue, securityLog => securityLog.UserId == userId) + .WhereIf(!userName.IsNullOrWhiteSpace(), securityLog => securityLog.UserName == userName) + .WhereIf(!clientId.IsNullOrWhiteSpace(), securityLog => securityLog.ClientId == clientId) + .WhereIf(!correlationId.IsNullOrWhiteSpace(), + securityLog => securityLog.CorrelationId == correlationId); + } + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentitySecurityLogRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentitySecurityLogRepository_Tests.cs new file mode 100644 index 0000000000..434f74706d --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentitySecurityLogRepository_Tests.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.Identity.EntityFrameworkCore +{ + public class IdentitySecurityLogRepository_Tests : IdentitySecurityLogRepository_Tests + { + + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentitySecurityLogRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentitySecurityLogRepository_Tests.cs new file mode 100644 index 0000000000..85d496fdb2 --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentitySecurityLogRepository_Tests.cs @@ -0,0 +1,10 @@ +using Xunit; + +namespace Volo.Abp.Identity.MongoDB +{ + [Collection(MongoTestCollection.Name)] + public class IdentitySecurityLogRepository_Tests : IdentitySecurityLogRepository_Tests + { + + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs index 9258be16af..79dd858c20 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs @@ -1,9 +1,10 @@ -using System; +using System; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; +using Volo.Abp.SecurityLog; namespace Volo.Abp.Identity { @@ -14,6 +15,7 @@ namespace Volo.Abp.Identity private readonly IIdentityClaimTypeRepository _identityClaimTypeRepository; private readonly IIdentityRoleRepository _roleRepository; private readonly IOrganizationUnitRepository _organizationUnitRepository; + private readonly IIdentitySecurityLogRepository _identitySecurityLogRepository; private readonly ILookupNormalizer _lookupNormalizer; private readonly IdentityTestData _testData; private readonly OrganizationUnitManager _organizationUnitManager; @@ -31,6 +33,7 @@ namespace Volo.Abp.Identity IIdentityClaimTypeRepository identityClaimTypeRepository, IIdentityRoleRepository roleRepository, IOrganizationUnitRepository organizationUnitRepository, + IIdentitySecurityLogRepository identitySecurityLogRepository, ILookupNormalizer lookupNormalizer, IdentityTestData testData, OrganizationUnitManager organizationUnitManager) @@ -43,6 +46,7 @@ namespace Volo.Abp.Identity _testData = testData; _organizationUnitRepository = organizationUnitRepository; _organizationUnitManager = organizationUnitManager; + _identitySecurityLogRepository = identitySecurityLogRepository; } public async Task Build() @@ -51,6 +55,7 @@ namespace Volo.Abp.Identity await AddOrganizationUnits(); await AddUsers(); await AddClaimTypes(); + await AddSecurityLogs(); } private async Task AddRoles() @@ -69,7 +74,7 @@ namespace Volo.Abp.Identity } /* Creates OU tree as shown below: - * + * * - OU1 * - OU11 * - OU111 @@ -138,5 +143,30 @@ namespace Volo.Abp.Identity var ou = await _organizationUnitRepository.InsertAsync(new OrganizationUnit(_guidGenerator.Create(), displayName, parentId) { Code = code }); return ou; } + + private async Task AddSecurityLogs() + { + await _identitySecurityLogRepository.InsertAsync(new IdentitySecurityLog(_guidGenerator, new SecurityLogInfo + { + ApplicationName = "Test-ApplicationName", + Identity = "Test-Identity", + Action = "Test-Action", + UserId = _testData.UserJohnId, + UserName = "john.nash", + + CreationTime = new DateTime(2020, 01, 01, 10, 0, 0) + })); + + await _identitySecurityLogRepository.InsertAsync(new IdentitySecurityLog(_guidGenerator, new SecurityLogInfo + { + ApplicationName = "Test-ApplicationName", + Identity = "Test-Identity", + Action = "Test-Action", + UserId = _testData.UserDavidId, + UserName = "david", + + CreationTime = new DateTime(2020, 01, 02, 10, 0, 0) + })); + } } -} \ No newline at end of file +} diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentitySecurityLogRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentitySecurityLogRepository_Tests.cs new file mode 100644 index 0000000000..13ff8a06a3 --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentitySecurityLogRepository_Tests.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Modularity; +using Xunit; + +namespace Volo.Abp.Identity +{ + public abstract class IdentitySecurityLogRepository_Tests : AbpIdentityTestBase + where TStartupModule : IAbpModule + { + protected IIdentitySecurityLogRepository RoleRepository { get; } + protected IdentityTestData TestData { get; } + + protected IdentitySecurityLogRepository_Tests() + { + RoleRepository = GetRequiredService(); + TestData = GetRequiredService(); + } + + [Fact] + public async Task GetListAsync() + { + var logs = await RoleRepository.GetListAsync(); + logs.ShouldNotBeEmpty(); + logs.ShouldContain(x => x.ApplicationName == "Test-ApplicationName" && x.UserId == TestData.UserJohnId); + logs.ShouldContain(x => x.ApplicationName == "Test-ApplicationName" && x.UserId == TestData.UserDavidId); + } + + [Fact] + public async Task GetCountAsync() + { + var count = await RoleRepository.GetCountAsync(); + count.ShouldBe(2); + } + } +} diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index 0a159562c0..d54346ce00 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -96,8 +96,5 @@ "commitizen": { "path": "cz-conventional-changelog" } - }, - "resolutions": { - "@ngx-validate/core": "^0.0.8" } } diff --git a/npm/ng-packs/packages/account/src/lib/tests/account.service.spec.ts b/npm/ng-packs/packages/account/src/lib/tests/account.service.spec.ts index aa7d7f90a4..b538713bb7 100644 --- a/npm/ng-packs/packages/account/src/lib/tests/account.service.spec.ts +++ b/npm/ng-packs/packages/account/src/lib/tests/account.service.spec.ts @@ -15,7 +15,7 @@ describe('AccountService', () => { beforeEach(() => (spectator = createHttp())); it('should send a GET to find tenant', () => { - spectator.get(Store).selectSnapshot.andReturn('https://abp.io'); + spectator.inject(Store).selectSnapshot.andReturn('https://abp.io'); spectator.service.findTenant('test').subscribe(); spectator.expectOne( 'https://abp.io/api/abp/multi-tenancy/tenants/by-name/test', @@ -30,7 +30,7 @@ describe('AccountService', () => { password: 'test1234', appName: 'Angular', } as RegisterRequest; - spectator.get(Store).selectSnapshot.andReturn('https://abp.io'); + spectator.inject(Store).selectSnapshot.andReturn('https://abp.io'); spectator.service.register(mock).subscribe(); const req = spectator.expectOne('https://abp.io/api/account/register', HttpMethod.POST); expect(req.request.body).toEqual(mock); diff --git a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html index 47c1355077..b7c777a449 100644 --- a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html +++ b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html @@ -1,4 +1,6 @@
; @Output() readonly checkedKeysChange = new EventEmitter(); @Output() readonly expandedKeysChange = new EventEmitter(); @Output() readonly selectedNodeChange = new EventEmitter(); + @Output() readonly dropOver = new EventEmitter(); + @Input() draggable: boolean; @Input() checkable: boolean; @Input() checkStrictly: boolean; @Input() checkedKeys = []; @@ -29,6 +37,10 @@ export class TreeComponent { @Input() expandedKeys: string[] = []; @Input() selectedNode: any; @Input() isNodeSelected = node => this.selectedNode?.id === node.key; + @Input() beforeDrop = (event: NzFormatBeforeDropEvent) => { + this.dropPosition = event.pos; + return of(false); + }; onSelectedNodeChange(node) { this.selectedNode = node.origin.entity; @@ -44,4 +56,12 @@ export class TreeComponent { this.expandedKeys = [...event.keys]; this.expandedKeysChange.emit(event.keys); } + + onDrop(event: DropEvent) { + event.event.stopPropagation(); + event.event.preventDefault(); + event.pos = this.dropPosition; + + this.dropOver.emit(event); + } } diff --git a/npm/ng-packs/packages/core/src/lib/tests/api.interceptor.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/api.interceptor.spec.ts index b4f1dcd408..8285a6a9f4 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/api.interceptor.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/api.interceptor.spec.ts @@ -21,8 +21,8 @@ describe('ApiInterceptor', () => { beforeEach(() => { spectator = createService(); interceptor = spectator.service; - store = spectator.get(Store); - oauthService = spectator.get(OAuthService); + store = spectator.inject(Store); + oauthService = spectator.inject(OAuthService); }); it('should add headers to http request', done => { diff --git a/npm/ng-packs/packages/core/src/lib/tests/application-configuration.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/application-configuration.service.spec.ts index 1fccc14c8f..8bbdabda80 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/application-configuration.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/application-configuration.service.spec.ts @@ -14,7 +14,7 @@ describe('ApplicationConfigurationService', () => { beforeEach(() => (spectator = createHttp())); it('should send a GET to application-configuration API', () => { - spectator.get(Store).selectSnapshot.andReturn('https://abp.io'); + spectator.inject(Store).selectSnapshot.andReturn('https://abp.io'); spectator.service.getConfiguration().subscribe(); spectator.expectOne('https://abp.io/api/abp/application-configuration', HttpMethod.GET); }); diff --git a/npm/ng-packs/packages/core/src/lib/tests/auth.guard.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/auth.guard.spec.ts index 1e7f5bf585..5e20d7f568 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/auth.guard.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/auth.guard.spec.ts @@ -22,13 +22,13 @@ describe('AuthGuard', () => { }); it('should return true when user logged in', () => { - spectator.get(OAuthService).hasValidAccessToken.andReturn(true); + spectator.inject(OAuthService).hasValidAccessToken.andReturn(true); expect(guard.canActivate(null, null)).toBe(true); }); it('should return navigate to login page with redirectUrl state', () => { - const router = spectator.get(Router); - spectator.get(OAuthService).hasValidAccessToken.andReturn(false); + const router = spectator.inject(Router); + spectator.inject(OAuthService).hasValidAccessToken.andReturn(false); expect(guard.canActivate(null, { url: '/' } as any)).toBe(true); expect(router.navigate).toHaveBeenCalledWith(['/account/login'], { diff --git a/npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts index 4b0c9aa682..9a8f9b651e 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts @@ -102,7 +102,7 @@ describe('ConfigStateService', () => { beforeEach(() => { spectator = createService(); service = spectator.service; - store = spectator.get(Store); + store = spectator.inject(Store); }); test('should have the all ConfigState static methods', () => { const reg = /(?<=static )(.*)(?=\()/gm; diff --git a/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts index 0f9aa08c1a..d48fd4dde2 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts @@ -110,9 +110,9 @@ describe('ConfigState', () => { beforeEach(() => { spectator = createService(); - store = spectator.get(Store); + store = spectator.inject(Store); service = spectator.service; - state = new ConfigState(spectator.get(HttpClient), store); + state = new ConfigState(spectator.inject(HttpClient), store); }); describe('#getAll', () => { @@ -250,7 +250,7 @@ describe('ConfigState', () => { dispatchArg = a; return of(a); }); - const httpClient = spectator.get(HttpClient); + const httpClient = spectator.inject(HttpClient); httpClient.get.andReturn(res$); state.addData({ patchState, dispatch } as any).subscribe(); diff --git a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts index 216df7b681..4d5f53a9ba 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts @@ -167,8 +167,8 @@ describe('DynamicLayoutComponent', () => { beforeEach(async () => { spectator = createComponent(); - store = spectator.get(Store); - const routesService = spectator.get(RoutesService); + store = spectator.inject(Store); + const routesService = spectator.inject(RoutesService); routesService.add(routes); store.reset(storeData); diff --git a/npm/ng-packs/packages/core/src/lib/tests/locale.provider.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/locale.provider.spec.ts index b5c788635d..b07006a04d 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/locale.provider.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/locale.provider.spec.ts @@ -26,12 +26,12 @@ describe('LocaleProvider', () => { describe('#LOCALE_ID', () => { test('should equal to currentLang', async () => { spectator = createComponent(); - const localizationService = spectator.get(LocalizationService); + const localizationService = spectator.inject(LocalizationService); - expect(spectator.get(LOCALE_ID).valueOf()).toBe(localesMapping['en-US'] || 'en-US'); + expect(spectator.inject(LOCALE_ID).valueOf()).toBe(localesMapping['en-US'] || 'en-US'); (localizationService as any).currentLang = 'tr'; - expect(spectator.get(LOCALE_ID).valueOf()).toBe(localesMapping['tr'] || 'tr'); + expect(spectator.inject(LOCALE_ID).valueOf()).toBe(localesMapping['tr'] || 'tr'); }); }); }); diff --git a/npm/ng-packs/packages/core/src/lib/tests/localization.pipe.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/localization.pipe.spec.ts index 7444265e35..a062d2c18a 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/localization.pipe.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/localization.pipe.spec.ts @@ -12,8 +12,8 @@ describe('LocalizationPipe', () => { beforeEach(() => { spectator = createService(); - pipe = spectator.get(LocalizationPipe); - store = spectator.get(Store); + pipe = spectator.inject(LocalizationPipe); + store = spectator.inject(Store); }); it('should call getLocalization selector', () => { diff --git a/npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts index 9d6f6ba3bf..4dc9d51771 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts @@ -18,7 +18,7 @@ describe('LocalizationService', () => { beforeEach(() => { spectator = createService(); - store = spectator.get(Store); + store = spectator.inject(Store); service = spectator.service; }); @@ -52,7 +52,7 @@ describe('LocalizationService', () => { describe('#registerLocale', () => { it('should return registerLocale and then call setRouteReuse', () => { - const router = spectator.get(Router); + const router = spectator.inject(Router); const shouldReuseRoute = () => true; router.routeReuseStrategy = { shouldReuseRoute } as any; diff --git a/npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts index 1b6dabf05b..4c6356634b 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts @@ -42,7 +42,7 @@ describe('PermissionDirective', () => { }); it('should do nothing when condition is undefined', () => { - const spy = jest.spyOn(spectator.get(Store), 'select'); + const spy = jest.spyOn(spectator.inject(Store), 'select'); grantedPolicy$.next(false); expect(spy.mock.calls).toHaveLength(0); }); diff --git a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts index dcfd27ab69..cd9108ec87 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts @@ -52,7 +52,7 @@ describe('PermissionGuard', () => { spectator = createService(); guard = spectator.service; routes = spectator.inject(RoutesService); - store = spectator.get(Store); + store = spectator.inject(Store); }); it('should return true when the grantedPolicy is true', done => { diff --git a/npm/ng-packs/packages/core/src/lib/tests/profile-state.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/profile-state.service.spec.ts index 10db71f6c6..967957b537 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/profile-state.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/profile-state.service.spec.ts @@ -13,7 +13,7 @@ describe('ProfileStateService', () => { beforeEach(() => { spectator = createService(); service = spectator.service; - store = spectator.get(Store); + store = spectator.inject(Store); }); test('should have the all ProfileState static methods', () => { const reg = /(?<=static )(.*)(?=\()/gm; diff --git a/npm/ng-packs/packages/core/src/lib/tests/profile.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/profile.service.spec.ts index 6f4d7f3041..4c7b7ba3c1 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/profile.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/profile.service.spec.ts @@ -14,14 +14,14 @@ describe('ProfileService', () => { beforeEach(() => (spectator = createHttp())); it('should send a GET to my-profile API', () => { - spectator.get(Store).selectSnapshot.andReturn('https://abp.io'); + spectator.inject(Store).selectSnapshot.andReturn('https://abp.io'); spectator.service.get().subscribe(); spectator.expectOne('https://abp.io/api/identity/my-profile', HttpMethod.GET); }); it('should send a POST to change-password API', () => { const mock = { currentPassword: 'test', newPassword: 'test' }; - spectator.get(Store).selectSnapshot.andReturn('https://abp.io'); + spectator.inject(Store).selectSnapshot.andReturn('https://abp.io'); spectator.service.changePassword(mock).subscribe(); const req = spectator.expectOne( 'https://abp.io/api/identity/my-profile/change-password', @@ -38,7 +38,7 @@ describe('ProfileService', () => { surname: 'Doe', phoneNumber: '+123456', }; - spectator.get(Store).selectSnapshot.andReturn('https://abp.io'); + spectator.inject(Store).selectSnapshot.andReturn('https://abp.io'); spectator.service.update(mock).subscribe(); const req = spectator.expectOne('https://abp.io/api/identity/my-profile', HttpMethod.PUT); expect(req.request.body).toEqual(mock); diff --git a/npm/ng-packs/packages/core/src/lib/tests/profile.state.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/profile.state.spec.ts index 380ea53b1c..2ab5f1dff2 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/profile.state.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/profile.state.spec.ts @@ -26,7 +26,7 @@ describe('ProfileState', () => { beforeEach(() => { spectator = createService(); - profileService = spectator.get(ProfileService); + profileService = spectator.inject(ProfileService); state = new ProfileState(profileService); }); diff --git a/npm/ng-packs/packages/core/src/lib/tests/replaceable-components.state.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/replaceable-components.state.spec.ts index dc113c433c..be063c4844 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/replaceable-components.state.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/replaceable-components.state.spec.ts @@ -25,7 +25,7 @@ describe('ReplaceableComponentsState', () => { }); it('should add a component to the state', () => { - const store = spectator.get(Store); + const store = spectator.inject(Store); expect(store.selectSnapshot(ReplaceableComponentsState.getAll)).toEqual([]); store.dispatch(new AddReplaceableComponent({ component: DummyComponent, key: 'Dummy' })); expect(store.selectSnapshot(ReplaceableComponentsState.getComponent('Dummy'))).toEqual({ @@ -35,7 +35,7 @@ describe('ReplaceableComponentsState', () => { }); it('should replace a exist component', () => { - const store = spectator.get(Store); + const store = spectator.inject(Store); store.dispatch(new AddReplaceableComponent({ component: DummyComponent, key: 'Dummy' })); store.dispatch(new AddReplaceableComponent({ component: null, key: 'Dummy' })); expect(store.selectSnapshot(ReplaceableComponentsState.getComponent('Dummy'))).toEqual({ @@ -47,7 +47,7 @@ describe('ReplaceableComponentsState', () => { it('should call reloadRoute when reload parameter is given as true to AddReplaceableComponent', async () => { const spy = jest.spyOn(router, 'navigateByUrl'); - const store = spectator.get(Store); + const store = spectator.inject(Store); store.dispatch(new AddReplaceableComponent({ component: DummyComponent, key: 'Dummy' })); store.dispatch(new AddReplaceableComponent({ component: null, key: 'Dummy' }, true)); diff --git a/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts index 96bbc197d0..601c9dd6d2 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts @@ -20,7 +20,7 @@ describe('HttpClient testing', () => { beforeEach(() => { spectator = createHttp(); - store = spectator.get(Store); + store = spectator.inject(Store); store.reset({ ConfigState: { environment: { diff --git a/npm/ng-packs/packages/core/src/lib/tests/session-state.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/session-state.service.spec.ts index cff6f9e239..d1c4dd5024 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/session-state.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/session-state.service.spec.ts @@ -17,7 +17,7 @@ describe('SessionStateService', () => { beforeEach(() => { spectator = createService(); service = spectator.service; - store = spectator.get(Store); + store = spectator.inject(Store); }); test('should have the all SessionState static methods', () => { const reg = /(?<=static )(.*)(?=\()/gm; diff --git a/npm/ng-packs/packages/feature-management/src/lib/tests/feature-management-state.service.spec.ts b/npm/ng-packs/packages/feature-management/src/lib/tests/feature-management-state.service.spec.ts index 59dc3701a2..5d59755cbd 100644 --- a/npm/ng-packs/packages/feature-management/src/lib/tests/feature-management-state.service.spec.ts +++ b/npm/ng-packs/packages/feature-management/src/lib/tests/feature-management-state.service.spec.ts @@ -16,7 +16,7 @@ describe('FeatureManagementStateService', () => { beforeEach(() => { spectator = createService(); service = spectator.service; - store = spectator.get(Store); + store = spectator.inject(Store); }); test('should have the all FeatureManagementState static methods', () => { diff --git a/npm/ng-packs/packages/identity/src/lib/tests/identity-state.service.spec.ts b/npm/ng-packs/packages/identity/src/lib/tests/identity-state.service.spec.ts index dcf3193eea..ac0952d9c0 100644 --- a/npm/ng-packs/packages/identity/src/lib/tests/identity-state.service.spec.ts +++ b/npm/ng-packs/packages/identity/src/lib/tests/identity-state.service.spec.ts @@ -13,7 +13,7 @@ describe('IdentityStateService', () => { beforeEach(() => { spectator = createService(); service = spectator.service; - store = spectator.get(Store); + store = spectator.inject(Store); }); test('should have the all IdentityState static methods', () => { diff --git a/npm/ng-packs/packages/permission-management/src/lib/tests/permission-management-state.service.spec.ts b/npm/ng-packs/packages/permission-management/src/lib/tests/permission-management-state.service.spec.ts index f1d344c7ac..bdc2c9d490 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/tests/permission-management-state.service.spec.ts +++ b/npm/ng-packs/packages/permission-management/src/lib/tests/permission-management-state.service.spec.ts @@ -16,7 +16,7 @@ describe('PermissionManagementStateService', () => { beforeEach(() => { spectator = createService(); service = spectator.service; - store = spectator.get(Store); + store = spectator.inject(Store); }); test('should have the all PermissionManagementState static methods', () => { const reg = /(?<=static )(.*)(?=\()/gm; diff --git a/npm/ng-packs/packages/tenant-management/src/lib/tests/tenant-management-state.service.spec.ts b/npm/ng-packs/packages/tenant-management/src/lib/tests/tenant-management-state.service.spec.ts index bd9017a2c7..befd819b70 100644 --- a/npm/ng-packs/packages/tenant-management/src/lib/tests/tenant-management-state.service.spec.ts +++ b/npm/ng-packs/packages/tenant-management/src/lib/tests/tenant-management-state.service.spec.ts @@ -16,7 +16,7 @@ describe('TenantManagementStateService', () => { beforeEach(() => { spectator = createService(); service = spectator.service; - store = spectator.get(Store); + store = spectator.inject(Store); }); test('should have the all TenantManagementState static methods', () => { diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/tests/form-props.util.spec.ts b/npm/ng-packs/packages/theme-shared/extensions/src/tests/form-props.util.spec.ts index af1edbb9fb..123912cb9a 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/tests/form-props.util.spec.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/tests/form-props.util.spec.ts @@ -126,8 +126,8 @@ describe('Form Prop Utils', () => { function* getInjected(spectator: SpectatorService) { yield spectator.service; - yield spectator.get(EXTENSIONS_IDENTIFIER); - yield spectator.get(LocalizationService); + yield spectator.inject(EXTENSIONS_IDENTIFIER); + yield spectator.inject(LocalizationService); } interface Foo { diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/append-content.token.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/append-content.token.spec.ts index bcf48a0125..fe3b0ac37c 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/append-content.token.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/append-content.token.spec.ts @@ -15,8 +15,8 @@ describe('AppendContentToken', () => { beforeEach(() => (spectator = createComponent())); it('should insert a style element to the DOM', () => { - spectator.get(THEME_SHARED_APPEND_CONTENT); - expect(spectator.get(DomInsertionService).has(styles)).toBe(true); + spectator.inject(THEME_SHARED_APPEND_CONTENT); + expect(spectator.inject(DomInsertionService).has(styles)).toBe(true); }); it('should be loaded the chart.js', done => { @@ -25,6 +25,6 @@ describe('AppendContentToken', () => { done(); }); - spectator.get(THEME_SHARED_APPEND_CONTENT); + spectator.inject(THEME_SHARED_APPEND_CONTENT); }); }); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts index bb8522c4a5..1712baef99 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts @@ -54,8 +54,8 @@ describe('BreadcrumbComponent', () => { beforeEach(() => { spectator = createRouting(); - routes = spectator.get(RoutesService); - store = spectator.get(Store); + routes = spectator.inject(RoutesService); + store = spectator.inject(Store); }); it('should display the breadcrumb', async () => { diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts index bacbb93ed0..89e9239b6e 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts @@ -52,7 +52,7 @@ describe('ErrorHandler', () => { beforeEach(() => { spectator = createService(); service = spectator.service; - store = spectator.get(Store); + store = spectator.inject(Store); store.selectSnapshot = jest.fn(() => '/x'); }); @@ -189,7 +189,7 @@ describe('ErrorHandler', () => { test('should call error method of ConfirmationService when authenticated error occurs with _AbpErrorFormat header', done => { spectator - .get(Actions) + .inject(Actions) .pipe(ofActionDispatched(Navigate)) .subscribe(({ path, queryParams, extras }) => { expect(path).toEqual(['/account/login']); @@ -281,7 +281,7 @@ describe('ErrorHandler with custom error component', () => { beforeEach(() => { spectator = createService(); service = spectator.service; - store = spectator.get(Store); + store = spectator.inject(Store); store.selectSnapshot = jest.fn(() => '/x'); }); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/loader-bar.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/loader-bar.component.spec.ts index e363dacfd1..2ae7c6aedf 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/loader-bar.component.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/loader-bar.component.spec.ts @@ -22,7 +22,7 @@ describe('LoaderBarComponent', () => { spectator = createHost(''); spectator.component.intervalPeriod = 1; spectator.component.stopDelay = 1; - router = spectator.get(Router); + router = spectator.inject(Router); (router as any).events = events$; }); @@ -34,7 +34,7 @@ describe('LoaderBarComponent', () => { it('should increase the progressLevel', done => { spectator.detectChanges(); - spectator.get(Store).dispatch(new StartLoader(new HttpRequest('GET', 'test'))); + spectator.inject(Store).dispatch(new StartLoader(new HttpRequest('GET', 'test'))); spectator.detectChanges(); setTimeout(() => { expect(spectator.component.progressLevel > 0).toBeTruthy(); @@ -44,7 +44,7 @@ describe('LoaderBarComponent', () => { test.skip('should be interval unsubscribed', done => { spectator.detectChanges(); - spectator.get(Store).dispatch(new StartLoader(new HttpRequest('GET', 'test'))); + spectator.inject(Store).dispatch(new StartLoader(new HttpRequest('GET', 'test'))); expect(spectator.component.interval.closed).toBe(false); timer(400).subscribe(() => { @@ -73,7 +73,7 @@ describe('LoaderBarComponent', () => { (router as any).events.next(new NavigationStart(1, 'test')); expect(spectator.component.interval.closed).toBe(false); - spectator.get(Store).dispatch(new StopLoader(new HttpRequest('GET', 'test'))); + spectator.inject(Store).dispatch(new StopLoader(new HttpRequest('GET', 'test'))); expect(spectator.component.progressLevel).toBe(100); timer(2).subscribe(() => { diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/modal-container.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/modal-container.component.spec.ts index 4ee654e9bd..9cb45127e5 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/modal-container.component.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/modal-container.component.spec.ts @@ -23,7 +23,7 @@ describe('ModalContainerComponent', () => { let foo = document.querySelector('div.foo'); expect(foo).toBeNull(); - const cfResolver = spectator.get(ComponentFactoryResolver); + const cfResolver = spectator.inject(ComponentFactoryResolver); const factory = cfResolver.resolveComponentFactory(TestComponent); componentRef = spectator.component.container.createComponent(factory); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/modal.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/modal.component.spec.ts index 00562c4780..b321ee4542 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/modal.component.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/modal.component.spec.ts @@ -78,7 +78,7 @@ describe('ModalComponent', () => { }); afterEach(() => { - const modalService = spectator.get(ModalService); + const modalService = spectator.inject(ModalService); modalService.clearModal(); }); @@ -120,7 +120,7 @@ describe('ModalComponent', () => { }); it('should open the confirmation popup and works correct', async () => { - const confirmationService = spectator.get(ConfirmationService); + const confirmationService = spectator.inject(ConfirmationService); const warnSpy = jest.spyOn(confirmationService, 'warn'); await wait0ms(); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/validation-utils.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/validation-utils.spec.ts index 3cda3b5403..35a46e1ae9 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/validation-utils.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/validation-utils.spec.ts @@ -22,7 +22,7 @@ describe('ValidationUtils', () => { describe('#getPasswordValidators', () => { it('should return password valdiators', () => { - const store = spectator.get(Store); + const store = spectator.inject(Store); store.reset({ ConfigState: { setting: { diff --git a/npm/ng-packs/scripts/build.ts b/npm/ng-packs/scripts/build.ts index 9b90d3a4c1..8d442f0740 100644 --- a/npm/ng-packs/scripts/build.ts +++ b/npm/ng-packs/scripts/build.ts @@ -23,7 +23,7 @@ import fse from 'fs-extra'; '--no-watch', '--sync', '--packages', - '@abp/ng.core,@abp/ng.theme.shared', + '@abp/ng.core,@abp/ng.theme.shared,@abp/ng.components', ], { stdout: 'inherit', cwd: '../' }, ); @@ -38,7 +38,7 @@ import fse from 'fs-extra'; '--no-watch', '--all-packages', '--excluded-packages', - '@abp/ng.core,@abp/ng.theme.shared,@abp/ng.feature-management,@abp/ng.permission-management', + '@abp/ng.core,@abp/ng.theme.shared,@abp/ng.components,@abp/ng.feature-management,@abp/ng.permission-management', ], { stdout: 'inherit', cwd: '../' }, ); diff --git a/npm/ng-packs/scripts/publish.ts b/npm/ng-packs/scripts/publish.ts index 3b16992357..99f38733a2 100644 --- a/npm/ng-packs/scripts/publish.ts +++ b/npm/ng-packs/scripts/publish.ts @@ -21,7 +21,7 @@ const publish = async () => { } const registry = program.preview - ? 'https://www.myget.org/F/abp-nightly/npm' + ? 'https://www.myget.org/F/abp-nightly/auth/8f2a5234-1bce-4dc7-b976-2983078590a9/npm/' : 'https://registry.npmjs.org'; try { diff --git a/npm/ng-packs/yarn.lock b/npm/ng-packs/yarn.lock index 6c27814650..c94fdbb1bc 100644 --- a/npm/ng-packs/yarn.lock +++ b/npm/ng-packs/yarn.lock @@ -2319,10 +2319,10 @@ rxjs "6.5.5" webpack-sources "1.4.3" -"@ngx-validate/core@^0.0.8", "@ngx-validate/core@^0.0.9": - version "0.0.8" - resolved "https://registry.yarnpkg.com/@ngx-validate/core/-/core-0.0.8.tgz#8577405eb1af0f5002cdda7a86fbcda56280f116" - integrity sha512-caIG5ao76Xhf7T+pNA8crnpAwK0yqj3i0OAUGZRUq1W+kNgz+ZnrSd4F9an/W4g+38u/8gfUVvsfsm07ju6qYA== +"@ngx-validate/core@^0.0.9": + version "0.0.9" + resolved "https://registry.yarnpkg.com/@ngx-validate/core/-/core-0.0.9.tgz#c5baea9e6f2f28c70d1adaf1edde5a9bcc8929c0" + integrity sha512-bvgwGr3l47gyxqsfKkI8c7UNMlv8ct/OvwYVDjYI7GBt0A+nhBb+xFmirWbBkMT64bUI0Y8pWIiB5qiewPG1WA== dependencies: tslib "^1.9.0" @@ -2402,13 +2402,13 @@ "@octokit/types" "^5.0.0" "@octokit/endpoint@^6.0.1": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.3.tgz#dd09b599662d7e1b66374a177ab620d8cdf73487" - integrity sha512-Y900+r0gIz+cWp6ytnkibbD95ucEzDSKzlEnaWS52hbCDNcCJYO5mRmWW7HRAnDc7am+N/5Lnd8MppSaTYx1Yg== + version "6.0.4" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.4.tgz#da3eafdee1fabd6e5b6ca311efcba26f0dd99848" + integrity sha512-ZJHIsvsClEE+6LaZXskDvWIqD3Ao7+2gc66pRG5Ov4MQtMvCU9wGu1TItw9aGNmRuU9x3Fei1yb+uqGaQnm0nw== dependencies: "@octokit/types" "^5.0.0" is-plain-object "^3.0.0" - universal-user-agent "^5.0.0" + universal-user-agent "^6.0.0" "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" @@ -2454,9 +2454,9 @@ once "^1.4.0" "@octokit/request@^5.2.0": - version "5.4.5" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.5.tgz#8df65bd812047521f7e9db6ff118c06ba84ac10b" - integrity sha512-atAs5GAGbZedvJXXdjtKljin+e2SltEs48B3naJjqWupYl2IUBbB/CJisyjbNHcKpHzb3E+OYEZ46G8eakXgQg== + version "5.4.6" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.6.tgz#e8cc8d4cfc654d30428ea92aaa62168fd5ead7eb" + integrity sha512-9r8Sn4CvqFI9LDLHl9P17EZHwj3ehwQnTpTE+LEneb0VBBqSiI/VS4rWIBfBhDrDs/aIGEGZRSB0QWAck8u+2g== dependencies: "@octokit/endpoint" "^6.0.1" "@octokit/request-error" "^2.0.0" @@ -2465,7 +2465,7 @@ is-plain-object "^3.0.0" node-fetch "^2.3.0" once "^1.4.0" - universal-user-agent "^5.0.0" + universal-user-agent "^6.0.0" "@octokit/rest@^16.28.4": version "16.43.2" @@ -2579,9 +2579,9 @@ integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== "@sinonjs/commons@^1.7.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d" - integrity sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q== + version "1.8.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" + integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw== dependencies: type-detect "4.0.8" @@ -4116,9 +4116,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001061, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001097: - version "1.0.30001100" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001100.tgz#2a58615e0c01cf716ab349b20ca4d86ef944aa4e" - integrity sha512-0eYdp1+wFCnMlCj2oudciuQn2B9xAFq3WpgpcBIZTxk/1HNA/O2YA7rpeYhnOqsqAJq1AHUgx6i1jtafg7m2zA== + version "1.0.30001102" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001102.tgz#3275e7a8d09548f955f665e532df88de0b63741a" + integrity sha512-fOjqRmHjRXv1H1YD6QVLb96iKqnu17TjcLSaX64TwhGYed0P1E1CCWZ9OujbbK4Z/7zax7zAzvQidzdtjx8RcA== canonical-path@1.0.0: version "1.0.0" @@ -5697,9 +5697,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.488: - version "1.3.498" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.498.tgz#fd7188c8a49d6d0b5df1df55a1f1a4bf2c177457" - integrity sha512-W1hGwaQEU8j9su2jeAr3aabkPuuXw+j8t73eajGAkEJWbfWiwbxBwQN/8Qmv2qCy3uCDm2rOAaZneYQM8VGC4w== + version "1.3.499" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.499.tgz#06949f19877dafa42915e57dfeb4c1cfb86a8649" + integrity sha512-y7FwtQm/8xuLMnYQfBQDYzCpNn+VkSnf4c3Km5TWMNXg7JA5RQBuxmcLaKdDVcIK0K5xGIa7TlxpRt4BdNxNoA== elliptic@^6.0.0, elliptic@^6.5.2: version "6.5.3" @@ -8583,9 +8583,9 @@ less-loader@6.1.0: schema-utils "^2.6.6" less@^3.10.3, less@^3.11.1: - version "3.12.0" - resolved "https://registry.yarnpkg.com/less/-/less-3.12.0.tgz#f23f9bd94ba72495994865d84e3b5ac6ee8a0363" - integrity sha512-3mmSHFRP9hGxxQgAKgChfau1LO3ksV/zyZf1qd2ENyBV778NA9Ids99wFRA20jE+5prT7oScKod8PoGlxSe1gg== + version "3.12.2" + resolved "https://registry.yarnpkg.com/less/-/less-3.12.2.tgz#157e6dd32a68869df8859314ad38e70211af3ab4" + integrity sha512-+1V2PCMFkL+OIj2/HrtrvZw0BC0sYLMICJfbQjuj/K8CEnlrFX6R5cKKgzzttsZDHyxQNL1jqMREjKN3ja/E3Q== dependencies: tslib "^1.10.0" optionalDependencies: @@ -9291,7 +9291,7 @@ mkdirp-promise@^5.0.1: dependencies: mkdirp "*" -mkdirp@*, mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: +mkdirp@*, mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -12641,7 +12641,7 @@ stylus-loader@3.0.2: lodash.clonedeep "^4.5.0" when "~3.6.x" -stylus@0.54.7, stylus@^0.54.7: +stylus@0.54.7: version "0.54.7" resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.7.tgz#c6ce4793965ee538bcebe50f31537bfc04d88cd2" integrity sha512-Yw3WMTzVwevT6ZTrLCYNHAFmanMxdylelL3hkWNgPMeTCpMwpV3nXjpOHuBXtFv7aiO2xRuQS6OoAdgkNcSNug== @@ -12655,6 +12655,20 @@ stylus@0.54.7, stylus@^0.54.7: semver "^6.0.0" source-map "^0.7.3" +stylus@^0.54.7: + version "0.54.8" + resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147" + integrity sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg== + dependencies: + css-parse "~2.0.0" + debug "~3.1.0" + glob "^7.1.6" + mkdirp "~1.0.4" + safer-buffer "^2.1.2" + sax "~1.2.4" + semver "^6.3.0" + source-map "^0.7.3" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -13062,9 +13076,9 @@ trim-off-newlines@^1.0.0: integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= ts-jest@^26.0.0: - version "26.1.2" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.2.tgz#dd2e832ffae9cb803361483b6a3010a6413dc475" - integrity sha512-V4SyBDO9gOdEh+AF4KtXJeP+EeI4PkOrxcA8ptl4o8nCXUVM5Gg/8ngGKneS5BsZaR9DXVQNqj9k+iqGAnpGow== + version "26.1.3" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.3.tgz#aac928a05fdf13e3e6dfbc8caec3847442667894" + integrity sha512-beUTSvuqR9SmKQEylewqJdnXWMVGJRFqSz2M8wKJe7GBMmLZ5zw6XXKSJckbHNMxn+zdB3guN2eOucSw2gBMnw== dependencies: bs-logger "0.x" buffer-from "1.x" @@ -13097,9 +13111,9 @@ ts-pnp@^1.1.6: integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== ts-toolbelt@^6.9.9: - version "6.13.6" - resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.13.6.tgz#4c9fad69bb3389323fe60982f18cd06b72f7d42a" - integrity sha512-qqIexrhqCNOuSRCrJMOKor8UJxA4DYMB6fNpBmRAKJgmLXNj8TAiuCrs7Nm08fva+MEdQhEXmsnjBQarNSIWZg== + version "6.13.11" + resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.13.11.tgz#46260d1cff0f2d635931df8d32239b73f2ed4f8d" + integrity sha512-QmvHwAofS1MAn1ndXCn2AVhxJLipaj4tK26SrhBTiydfgKtbLlU2efpIP/8Jocrc9ynNslZqrhqAesruJMlxCQ== tsickle@^0.38.1: version "0.38.1" @@ -13227,9 +13241,9 @@ typedarray@^0.0.6: integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript@^3.5.2, typescript@~3.9.5: - version "3.9.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a" - integrity sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw== + version "3.9.7" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" + integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== uglify-js@^3.1.4: version "3.10.0" @@ -13326,12 +13340,10 @@ universal-user-agent@^4.0.0: dependencies: os-name "^3.1.0" -universal-user-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-5.0.0.tgz#a3182aa758069bf0e79952570ca757de3579c1d9" - integrity sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q== - dependencies: - os-name "^3.1.0" +universal-user-agent@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" + integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== universalify@^0.1.0: version "0.1.2" diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.Designer.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.Designer.cs similarity index 92% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.Designer.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.Designer.cs index 23c25b58cd..e2ca97db45 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.Designer.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.Designer.cs @@ -10,8 +10,8 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { - [DbContext(typeof(IdentityServerHostMigrationsDbContext))] - [Migration("20200624023331_Initial")] + [DbContext(typeof(MyProjectNameMigrationsDbContext))] + [Migration("20200710064926_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -275,6 +275,95 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpEntityPropertyChanges"); }); + modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsAbandoned") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("JobArgs") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(1048576); + + b.Property("JobName") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("LastTryTime") + .HasColumnType("datetime2"); + + b.Property("NextTryTime") + .HasColumnType("datetime2"); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint") + .HasDefaultValue((byte)15); + + b.Property("TryCount") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((short)0); + + b.HasKey("Id"); + + b.HasIndex("IsAbandoned", "NextTryTime"); + + b.ToTable("AbpBackgroundJobs"); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ProviderName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpFeatureValues"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") @@ -399,6 +488,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.cs similarity index 91% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.cs index 9287186f86..2c82babc5b 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.cs @@ -39,6 +39,27 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpBackgroundJobs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), + JobName = table.Column(maxLength: 128, nullable: false), + JobArgs = table.Column(maxLength: 1048576, nullable: false), + TryCount = table.Column(nullable: false, defaultValue: (short)0), + CreationTime = table.Column(nullable: false), + NextTryTime = table.Column(nullable: false), + LastTryTime = table.Column(nullable: true), + IsAbandoned = table.Column(nullable: false, defaultValue: false), + Priority = table.Column(nullable: false, defaultValue: (byte)15) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -59,6 +80,21 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpFeatureValues", + columns: table => new + { + Id = table.Column(nullable: false), + Name = table.Column(maxLength: 128, nullable: false), + Value = table.Column(maxLength: 128, nullable: false), + ProviderName = table.Column(maxLength: 64, nullable: true), + ProviderKey = table.Column(maxLength: 64, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpFeatureValues", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpOrganizationUnits", columns: table => new @@ -123,6 +159,31 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpRoles", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpSecurityLogs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), + TenantId = table.Column(nullable: true), + ApplicationName = table.Column(maxLength: 96, nullable: true), + Identity = table.Column(maxLength: 96, nullable: true), + Action = table.Column(maxLength: 96, nullable: true), + UserId = table.Column(nullable: true), + UserName = table.Column(maxLength: 256, nullable: true), + TenantName = table.Column(maxLength: 64, nullable: true), + ClientId = table.Column(maxLength: 64, nullable: true), + CorrelationId = table.Column(maxLength: 64, nullable: true), + ClientIpAddress = table.Column(maxLength: 64, nullable: true), + BrowserInfo = table.Column(maxLength: 512, nullable: true), + CreationTime = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpSettings", columns: table => new @@ -887,6 +948,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpAuditLogs", columns: new[] { "TenantId", "UserId", "ExecutionTime" }); + migrationBuilder.CreateIndex( + name: "IX_AbpBackgroundJobs_IsAbandoned_NextTryTime", + table: "AbpBackgroundJobs", + columns: new[] { "IsAbandoned", "NextTryTime" }); + migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_AuditLogId", table: "AbpEntityChanges", @@ -902,6 +968,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpEntityPropertyChanges", column: "EntityChangeId"); + migrationBuilder.CreateIndex( + name: "IX_AbpFeatureValues_Name_ProviderName_ProviderKey", + table: "AbpFeatureValues", + columns: new[] { "Name", "ProviderName", "ProviderKey" }); + migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnitRoles_RoleId_OrganizationUnitId", table: "AbpOrganizationUnitRoles", @@ -932,6 +1003,26 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpRoles", column: "NormalizedName"); + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Action", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Action" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_ApplicationName", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "ApplicationName" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Identity", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Identity" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_UserId", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "UserId" }); + migrationBuilder.CreateIndex( name: "IX_AbpSettings_Name_ProviderName_ProviderKey", table: "AbpSettings", @@ -1020,12 +1111,18 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpAuditLogActions"); + migrationBuilder.DropTable( + name: "AbpBackgroundJobs"); + migrationBuilder.DropTable( name: "AbpClaimTypes"); migrationBuilder.DropTable( name: "AbpEntityPropertyChanges"); + migrationBuilder.DropTable( + name: "AbpFeatureValues"); + migrationBuilder.DropTable( name: "AbpOrganizationUnitRoles"); @@ -1035,6 +1132,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpRoleClaims"); + migrationBuilder.DropTable( + name: "AbpSecurityLogs"); + migrationBuilder.DropTable( name: "AbpSettings"); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs index 77d771b803..f06dda1edc 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs @@ -486,6 +486,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs similarity index 96% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs index 174de5bc94..00033c31b9 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs @@ -10,8 +10,8 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { - [DbContext(typeof(MyProjectNameMigrationsDbContext))] - [Migration("20200624023152_Initial")] + [DbContext(typeof(IdentityServerHostMigrationsDbContext))] + [Migration("20200710065039_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -275,95 +275,6 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpEntityPropertyChanges"); }); - modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnName("ConcurrencyStamp") - .HasColumnType("nvarchar(40)") - .HasMaxLength(40); - - b.Property("CreationTime") - .HasColumnName("CreationTime") - .HasColumnType("datetime2"); - - b.Property("ExtraProperties") - .HasColumnName("ExtraProperties") - .HasColumnType("nvarchar(max)"); - - b.Property("IsAbandoned") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false); - - b.Property("JobArgs") - .IsRequired() - .HasColumnType("nvarchar(max)") - .HasMaxLength(1048576); - - b.Property("JobName") - .IsRequired() - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); - - b.Property("LastTryTime") - .HasColumnType("datetime2"); - - b.Property("NextTryTime") - .HasColumnType("datetime2"); - - b.Property("Priority") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint") - .HasDefaultValue((byte)15); - - b.Property("TryCount") - .ValueGeneratedOnAdd() - .HasColumnType("smallint") - .HasDefaultValue((short)0); - - b.HasKey("Id"); - - b.HasIndex("IsAbandoned", "NextTryTime"); - - b.ToTable("AbpBackgroundJobs"); - }); - - modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("Name") - .IsRequired() - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); - - b.Property("ProviderKey") - .HasColumnType("nvarchar(64)") - .HasMaxLength(64); - - b.Property("ProviderName") - .HasColumnType("nvarchar(64)") - .HasMaxLength(64); - - b.Property("Value") - .IsRequired() - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); - - b.HasKey("Id"); - - b.HasIndex("Name", "ProviderName", "ProviderKey"); - - b.ToTable("AbpFeatureValues"); - }); - modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") @@ -488,6 +399,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs similarity index 96% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs index b98f3342be..f80a5d9936 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs @@ -39,27 +39,6 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); }); - migrationBuilder.CreateTable( - name: "AbpBackgroundJobs", - columns: table => new - { - Id = table.Column(nullable: false), - ExtraProperties = table.Column(nullable: true), - ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), - JobName = table.Column(maxLength: 128, nullable: false), - JobArgs = table.Column(maxLength: 1048576, nullable: false), - TryCount = table.Column(nullable: false, defaultValue: (short)0), - CreationTime = table.Column(nullable: false), - NextTryTime = table.Column(nullable: false), - LastTryTime = table.Column(nullable: true), - IsAbandoned = table.Column(nullable: false, defaultValue: false), - Priority = table.Column(nullable: false, defaultValue: (byte)15) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id); - }); - migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -80,21 +59,6 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); }); - migrationBuilder.CreateTable( - name: "AbpFeatureValues", - columns: table => new - { - Id = table.Column(nullable: false), - Name = table.Column(maxLength: 128, nullable: false), - Value = table.Column(maxLength: 128, nullable: false), - ProviderName = table.Column(maxLength: 64, nullable: true), - ProviderKey = table.Column(maxLength: 64, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpFeatureValues", x => x.Id); - }); - migrationBuilder.CreateTable( name: "AbpOrganizationUnits", columns: table => new @@ -159,6 +123,31 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpRoles", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpSecurityLogs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), + TenantId = table.Column(nullable: true), + ApplicationName = table.Column(maxLength: 96, nullable: true), + Identity = table.Column(maxLength: 96, nullable: true), + Action = table.Column(maxLength: 96, nullable: true), + UserId = table.Column(nullable: true), + UserName = table.Column(maxLength: 256, nullable: true), + TenantName = table.Column(maxLength: 64, nullable: true), + ClientId = table.Column(maxLength: 64, nullable: true), + CorrelationId = table.Column(maxLength: 64, nullable: true), + ClientIpAddress = table.Column(maxLength: 64, nullable: true), + BrowserInfo = table.Column(maxLength: 512, nullable: true), + CreationTime = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpSettings", columns: table => new @@ -923,11 +912,6 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpAuditLogs", columns: new[] { "TenantId", "UserId", "ExecutionTime" }); - migrationBuilder.CreateIndex( - name: "IX_AbpBackgroundJobs_IsAbandoned_NextTryTime", - table: "AbpBackgroundJobs", - columns: new[] { "IsAbandoned", "NextTryTime" }); - migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_AuditLogId", table: "AbpEntityChanges", @@ -943,11 +927,6 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpEntityPropertyChanges", column: "EntityChangeId"); - migrationBuilder.CreateIndex( - name: "IX_AbpFeatureValues_Name_ProviderName_ProviderKey", - table: "AbpFeatureValues", - columns: new[] { "Name", "ProviderName", "ProviderKey" }); - migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnitRoles_RoleId_OrganizationUnitId", table: "AbpOrganizationUnitRoles", @@ -978,6 +957,26 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpRoles", column: "NormalizedName"); + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Action", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Action" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_ApplicationName", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "ApplicationName" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Identity", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Identity" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_UserId", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "UserId" }); + migrationBuilder.CreateIndex( name: "IX_AbpSettings_Name_ProviderName_ProviderKey", table: "AbpSettings", @@ -1066,18 +1065,12 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpAuditLogActions"); - migrationBuilder.DropTable( - name: "AbpBackgroundJobs"); - migrationBuilder.DropTable( name: "AbpClaimTypes"); migrationBuilder.DropTable( name: "AbpEntityPropertyChanges"); - migrationBuilder.DropTable( - name: "AbpFeatureValues"); - migrationBuilder.DropTable( name: "AbpOrganizationUnitRoles"); @@ -1087,6 +1080,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpRoleClaims"); + migrationBuilder.DropTable( + name: "AbpSecurityLogs"); + migrationBuilder.DropTable( name: "AbpSettings"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs index 44c00e04d4..3129fab657 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs @@ -397,6 +397,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.Designer.cs similarity index 93% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.Designer.cs index d93e2804a6..4afc02af46 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.Designer.cs @@ -11,7 +11,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20200624023340_Initial")] + [Migration("20200710065052_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -399,6 +399,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.cs similarity index 92% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.cs index ad7940fa81..a0d5e132a9 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.cs @@ -123,6 +123,31 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpRoles", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpSecurityLogs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), + TenantId = table.Column(nullable: true), + ApplicationName = table.Column(maxLength: 96, nullable: true), + Identity = table.Column(maxLength: 96, nullable: true), + Action = table.Column(maxLength: 96, nullable: true), + UserId = table.Column(nullable: true), + UserName = table.Column(maxLength: 256, nullable: true), + TenantName = table.Column(maxLength: 64, nullable: true), + ClientId = table.Column(maxLength: 64, nullable: true), + CorrelationId = table.Column(maxLength: 64, nullable: true), + ClientIpAddress = table.Column(maxLength: 64, nullable: true), + BrowserInfo = table.Column(maxLength: 512, nullable: true), + CreationTime = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpSettings", columns: table => new @@ -515,6 +540,26 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpRoles", column: "NormalizedName"); + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Action", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Action" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_ApplicationName", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "ApplicationName" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Identity", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Identity" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_UserId", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "UserId" }); + migrationBuilder.CreateIndex( name: "IX_AbpSettings_Name_ProviderName_ProviderKey", table: "AbpSettings", @@ -586,6 +631,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpRoleClaims"); + migrationBuilder.DropTable( + name: "AbpSecurityLogs"); + migrationBuilder.DropTable( name: "AbpSettings"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index 157b210fc4..47b094f3c5 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -397,6 +397,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id")