From a36fda11e3914e13f472938d57865ff104ba6aa9 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Wed, 24 Jun 2020 17:28:02 +0800 Subject: [PATCH 01/32] Init UserSecurityLog. --- .../Volo.Abp.Security.csproj | 1 + .../SecurityLog/IUserSecurityLogStore.cs | 9 ++++ .../Users/SecurityLog/UserSecurityLogInfo.cs | 53 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs diff --git a/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj b/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj index 65aca85c88..6ffaac1232 100644 --- a/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj +++ b/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj @@ -16,6 +16,7 @@ + diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs new file mode 100644 index 0000000000..18d5b1c23e --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Users.SecurityLog +{ + public interface IUserSecurityLogStore + { + Task SaveAsync(UserSecurityLogInfo userSecurityLogInfo); + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs new file mode 100644 index 0000000000..5ecb8d9314 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Data; + +namespace Volo.Abp.Users.SecurityLog +{ + [Serializable] + public class UserSecurityLogInfo : IHasExtraProperties + { + /// + /// The name of the application or service writing user security logs. + /// Default: null. + /// + public string ApplicationName { get; set; } + + /// + /// Web, JWT, Identity, Identity_Server + /// + public string Identity { get; set; } + + /// + /// login_successful, login_failed, logout, change_pwd, refresh_token... + /// + 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 ClientName { get; set; } + + public string CorrelationId { get; set; } + + public string ClientIpAddress { get; set; } + + public string BrowserInfo { get; set; } + + public DateTime CreationTime { get; set; } + + public UserSecurityLogInfo() + { + ExtraProperties = new Dictionary(); + } + } +} From 58f0204e7b80eab68649dbe8d1387e8f92314c03 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 6 Jul 2020 10:31:58 +0800 Subject: [PATCH 02/32] Try to set GUID Id in the InsertAsync method of the EF Core repository. Resolve #4631 --- .../EntityFrameworkCore/EfCoreRepository.cs | 38 ++++++++++++++++--- .../Repositories/MongoDB/MongoDbRepository.cs | 1 + 2 files changed, 34 insertions(+), 5 deletions(-) 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 a48e5d7da5..6cb761eeef 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 @@ -10,6 +10,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 { @@ -28,9 +29,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 @@ -39,9 +43,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) @@ -65,7 +71,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); @@ -94,7 +100,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore } public override async Task FindAsync( - Expression> predicate, + Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) { @@ -172,16 +178,38 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return query; } + + protected virtual void CheckAndSetId(TEntity entity) + { + if (entity is IEntity entityWithGuidId) + { + TrySetGuidId(entity, entityWithGuidId); + } + } + + protected virtual void TrySetGuidId(TEntity entry, 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.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 6abcc70f0d..035de803af 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 @@ -49,6 +49,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB LocalEventBus = NullLocalEventBus.Instance; DistributedEventBus = NullDistributedEventBus.Instance; EntityChangeEventHelper = NullEntityChangeEventHelper.Instance; + GuidGenerator = SimpleGuidGenerator.Instance; } public override async Task InsertAsync( From 4af6d60a59441cd009fae235e62fb54470b9bba1 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 6 Jul 2020 10:38:22 +0800 Subject: [PATCH 03/32] Insert_Should_Set_Guid_Id unit test. --- .../EntityFrameworkCore/EfCoreRepository.cs | 4 ++-- .../Abp/MongoDB/Repositories/Repository_Basic_Tests.cs | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) 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 6cb761eeef..735353a454 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 @@ -183,11 +183,11 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore { if (entity is IEntity entityWithGuidId) { - TrySetGuidId(entity, entityWithGuidId); + TrySetGuidId(entityWithGuidId); } } - protected virtual void TrySetGuidId(TEntity entry, IEntity entity) + protected virtual void TrySetGuidId(IEntity entity) { if (entity.Id != default) { 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); + } } } From ecd69f333a40a17b74ee960f4c8ae473be678d55 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 6 Jul 2020 14:20:16 +0800 Subject: [PATCH 04/32] Add dataFormat option to the datatables column definitions. Resolve #4629 --- .../datatables/datatables-extensions.js | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) 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..dd749d0bc1 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,11 @@ column.targets = i; } + if (!column.render && column.dataFormat){ + var render = datatables.defaultRenderers[column.dataFormat]; + column.render = render ? render : ISOStringToDateTimeLocaleString(column.dataFormat); + } + if (column.rowAction) { customizeRowActionColumn(column); } @@ -330,18 +335,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); }; /************************************************************************ From 65957cbb6e2fa3c1d5b5a2c5d14cb527289a23be Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Wed, 8 Jul 2020 17:34:33 +0800 Subject: [PATCH 05/32] Add some infrastructure for security logs. --- .../Auditing/AspNetCoreAuditLogContributor.cs | 24 +----- .../AspNetCoreSecurityLogManager.cs | 74 +++++++++++++++++++ .../HttpContextWebClientInfoProvider.cs | 43 +++++++++++ .../WebClientInfo/IWebClientInfoProvider.cs | 9 +++ .../Abp/SecurityLog/AbpSecurityLogOptions.cs | 21 ++++++ .../SecurityLog/DefaultSecurityLogManager.cs | 34 +++++++++ .../Abp/SecurityLog/ISecurityLogManager.cs | 11 +++ .../Volo/Abp/SecurityLog/ISecurityLogStore.cs | 9 +++ .../SecurityLogInfo.cs} | 11 ++- .../Abp/SecurityLog/SimpleSecurityLogStore.cs | 22 ++++++ .../SecurityLog/IUserSecurityLogStore.cs | 9 --- .../IdentityServerSupportedLoginModel.cs | 3 + .../Account/Controllers/AccountController.cs | 25 ++++++- .../Pages/Account/AccountPageModel.cs | 11 +++ .../Pages/Account/Login.cshtml.cs | 8 +- 15 files changed, 277 insertions(+), 37 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/IWebClientInfoProvider.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/AbpSecurityLogOptions.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogStore.cs rename framework/src/Volo.Abp.Security/Volo/Abp/{Users/SecurityLog/UserSecurityLogInfo.cs => SecurityLog/SecurityLogInfo.cs} (82%) create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs delete mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs 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..4c60a6ce37 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs @@ -0,0 +1,74 @@ +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; + } + + public 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.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..0f5d40567c --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs @@ -0,0 +1,34 @@ +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 virtual Task CreateAsync() + { + return Task.FromResult(new SecurityLogInfo + { + ApplicationName = SecurityLogOptions.ApplicationName + }); + } + + public async Task SaveAsync(SecurityLogInfo securityLogInfo) + { + await SecurityLogStore.SaveAsync(securityLogInfo); + } + } +} 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..f762522509 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.SecurityLog +{ + public interface ISecurityLogManager + { + Task CreateAsync(); + + Task SaveAsync(SecurityLogInfo securityLogInfo); + } +} 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/Users/SecurityLog/UserSecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs similarity index 82% rename from framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs rename to framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs index 5ecb8d9314..11f46c7527 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using Volo.Abp.Data; -namespace Volo.Abp.Users.SecurityLog +namespace Volo.Abp.SecurityLog { [Serializable] - public class UserSecurityLogInfo : IHasExtraProperties + public class SecurityLogInfo : IHasExtraProperties { /// /// The name of the application or service writing user security logs. @@ -45,9 +45,14 @@ namespace Volo.Abp.Users.SecurityLog public DateTime CreationTime { get; set; } - public UserSecurityLogInfo() + 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..bc9c22c4df --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.SecurityLog +{ + public class SimpleSecurityLogStore : ISecurityLogStore, ITransientDependency + { + public ILogger Logger { get; set; } + + public SimpleSecurityLogStore(ILogger logger) + { + Logger = logger; + } + + public Task SaveAsync(SecurityLogInfo securityLogInfo) + { + Logger.LogInformation(securityLogInfo.ToString()); + return Task.FromResult(0); + } + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs deleted file mode 100644 index 18d5b1c23e..0000000000 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace Volo.Abp.Users.SecurityLog -{ - public interface IUserSecurityLogStore - { - Task SaveAsync(UserSecurityLogInfo userSecurityLogInfo); - } -} 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 60f55497da..af157ed629 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 @@ -15,6 +15,7 @@ using System.Threading.Tasks; using Volo.Abp.Account.Settings; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Volo.Abp.SecurityLog; using Volo.Abp.Settings; using Volo.Abp.Uow; @@ -127,6 +128,8 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); + await CreateSecurityLog("Login_" + result); + if (result.RequiresTwoFactor) { return RedirectToPage("./SendSecurityCode", new 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..38e8e7e7c2 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 @@ -7,6 +7,7 @@ using Volo.Abp.Account.Settings; using Volo.Abp.Account.Web.Areas.Account.Controllers.Models; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Identity; +using Volo.Abp.SecurityLog; using Volo.Abp.Settings; using Volo.Abp.Validation; using SignInResult = Microsoft.AspNetCore.Identity.SignInResult; @@ -25,14 +26,20 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers protected SignInManager SignInManager { get; } protected IdentityUserManager UserManager { get; } protected ISettingProvider SettingProvider { get; } + protected ISecurityLogManager SecurityLogManager { get; } - public AccountController(SignInManager signInManager, IdentityUserManager userManager, ISettingProvider settingProvider) + public AccountController( + SignInManager signInManager, + IdentityUserManager userManager, + ISettingProvider settingProvider, + ISecurityLogManager securityLogManager) { LocalizationResource = typeof(AccountResource); SignInManager = signInManager; UserManager = userManager; SettingProvider = settingProvider; + SecurityLogManager = securityLogManager; } [HttpPost] @@ -44,19 +51,23 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers ValidateLoginInfo(login); await ReplaceEmailToUsernameOfInputIfNeeds(login); - - return GetAbpLoginResult(await SignInManager.PasswordSignInAsync( + var loginResult = GetAbpLoginResult(await SignInManager.PasswordSignInAsync( login.UserNameOrEmailAddress, login.Password, login.RememberMe, true )); + + await CreateSecurityLog("Login_" + loginResult.Result); + + return loginResult; } [HttpGet] [Route("logout")] public virtual async Task Logout() { + await CreateSecurityLog("Logout"); await SignInManager.SignOutAsync(); } @@ -150,5 +161,13 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers throw new UserFriendlyException(L["LocalLoginDisabledMessage"]); } } + + protected virtual async Task CreateSecurityLog(string action) + { + var securityLog = await SecurityLogManager.CreateAsync(); + securityLog.Identity = "Web"; + securityLog.Action = action; + await SecurityLogManager.SaveAsync(securityLog); + } } } 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..d7fd0f8239 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,12 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; 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.Identity; +using Volo.Abp.SecurityLog; using IdentityUser = Volo.Abp.Identity.IdentityUser; namespace Volo.Abp.Account.Web.Pages.Account @@ -15,6 +17,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { public SignInManager SignInManager { get; set; } public IdentityUserManager UserManager { get; set; } + public ISecurityLogManager SecurityLogManager { get; } protected AccountPageModel() { @@ -76,5 +79,13 @@ namespace Volo.Abp.Account.Web.Pages.Account { return "~/"; //TODO: ??? } + + protected virtual async Task CreateSecurityLog(string action) + { + var securityLog = await SecurityLogManager.CreateAsync(); + securityLog.Identity = "Web"; + securityLog.Action = action; + await SecurityLogManager.SaveAsync(securityLog); + } } } 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 5251cb12f1..2916e60b4f 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 @@ -14,8 +14,8 @@ using Volo.Abp.Account.Settings; using Volo.Abp.Auditing; using Volo.Abp.Identity; using Volo.Abp.Security.Claims; +using Volo.Abp.SecurityLog; using Volo.Abp.Settings; -using Volo.Abp.Uow; using Volo.Abp.Validation; using IdentityUser = Volo.Abp.Identity.IdentityUser; @@ -83,7 +83,7 @@ namespace Volo.Abp.Account.Web.Pages.Account ValidateModel(); ExternalProviders = await GetExternalProviders(); - + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); await ReplaceEmailToUsernameOfInputIfNeeds(); @@ -95,6 +95,8 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); + await CreateSecurityLog(result.ToString()); + if (result.RequiresTwoFactor) { return RedirectToPage("./SendSecurityCode", new @@ -182,6 +184,8 @@ namespace Volo.Abp.Account.Web.Pages.Account bypassTwoFactor: true ); + await CreateSecurityLog(result.ToString()); + if (result.IsLockedOut) { throw new UserFriendlyException("Cannot proceed because user is locked out!"); From 73de02689f78726665326cb3da2c69c534bb799e Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 9 Jul 2020 10:34:50 +0800 Subject: [PATCH 06/32] Refactoring ISecurityLogManager. --- .../AspNetCoreSecurityLogManager.cs | 2 +- .../SecurityLog/DefaultSecurityLogManager.cs | 17 ++-- .../Abp/SecurityLog/ISecurityLogManager.cs | 7 +- .../Volo/Abp/SecurityLog/SecurityLogInfo.cs | 2 - .../IdentityServerSupportedLoginModel.cs | 9 +- .../Account/Controllers/AccountController.cs | 40 +++++---- .../Pages/Account/AccountPageModel.cs | 14 +-- .../Pages/Account/Login.cshtml.cs | 28 +++++- .../Pages/Account/Logout.cshtml.cs | 7 ++ .../AspNetCore/SignInResultExtensions.cs | 37 ++++++++ .../IdentitySecurityLogActionConsts.cs | 33 +++++++ .../IdentitySecurityLogIdentityConsts.cs | 11 +++ .../Identity/AbpIdentityResultExtensions.cs | 12 ++- .../Volo/Abp/Identity/SecurityLogEvent.cs | 18 ++++ .../Volo/Abp/Identity/SecurityLogHandler.cs | 85 +++++++++++++++++++ 15 files changed, 271 insertions(+), 51 deletions(-) create mode 100644 modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/SignInResultExtensions.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogActionConsts.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogIdentityConsts.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs 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 index 4c60a6ce37..55ece86be2 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs @@ -49,7 +49,7 @@ namespace Volo.Abp.AspNetCore.SecurityLog WebClientInfoProvider = webClientInfoProvider; } - public override async Task CreateAsync() + protected override async Task CreateAsync() { var securityLogInfo = await base.CreateAsync(); diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs index 0f5d40567c..fcc03965f2 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; @@ -18,17 +19,19 @@ namespace Volo.Abp.SecurityLog SecurityLogOptions = securityLogOptions.Value; } - public virtual Task CreateAsync() + public async Task SaveAsync(Action saveAction) + { + var securityLogInfo = await CreateAsync(); + saveAction?.Invoke(securityLogInfo); + await SecurityLogStore.SaveAsync(securityLogInfo); + } + + protected virtual Task CreateAsync() { return Task.FromResult(new SecurityLogInfo { ApplicationName = SecurityLogOptions.ApplicationName }); } - - public async Task SaveAsync(SecurityLogInfo securityLogInfo) - { - await SecurityLogStore.SaveAsync(securityLogInfo); - } } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs index f762522509..0bedfd0411 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs @@ -1,11 +1,10 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; namespace Volo.Abp.SecurityLog { public interface ISecurityLogManager { - Task CreateAsync(); - - Task SaveAsync(SecurityLogInfo securityLogInfo); + Task SaveAsync(Action saveAction); } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs index 11f46c7527..6185777b97 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -35,8 +35,6 @@ namespace Volo.Abp.SecurityLog public string ClientId { get; set; } - public string ClientName { get; set; } - public string CorrelationId { get; set; } public string ClientIpAddress { get; set; } 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 af157ed629..0d90972792 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,6 +14,8 @@ 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; @@ -128,7 +130,12 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); - await CreateSecurityLog("Login_" + result); + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = result.ToIdentitySecurityLogAction(), + UserName = LoginInput.UserNameOrEmailAddress + }); if (result.RequiresTwoFactor) { 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 38e8e7e7c2..69b57a42f4 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,9 @@ 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; @@ -26,20 +28,22 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers protected SignInManager SignInManager { get; } protected IdentityUserManager UserManager { get; } protected ISettingProvider SettingProvider { get; } - protected ISecurityLogManager SecurityLogManager { get; } + + protected ILocalEventBus LocalEventBus { get; } public AccountController( SignInManager signInManager, IdentityUserManager userManager, ISettingProvider settingProvider, - ISecurityLogManager securityLogManager) + ISecurityLogManager securityLogManager, + ILocalEventBus localEventBus) { LocalizationResource = typeof(AccountResource); SignInManager = signInManager; UserManager = userManager; SettingProvider = settingProvider; - SecurityLogManager = securityLogManager; + LocalEventBus = localEventBus; } [HttpPost] @@ -51,23 +55,33 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers ValidateLoginInfo(login); await ReplaceEmailToUsernameOfInputIfNeeds(login); - var loginResult = GetAbpLoginResult(await SignInManager.PasswordSignInAsync( + var signInResult = await SignInManager.PasswordSignInAsync( login.UserNameOrEmailAddress, login.Password, login.RememberMe, true - )); + ); - await CreateSecurityLog("Login_" + loginResult.Result); + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = signInResult.ToIdentitySecurityLogAction(), + UserName = login.UserNameOrEmailAddress + }); - return loginResult; + return GetAbpLoginResult(signInResult); } [HttpGet] [Route("logout")] public virtual async Task Logout() { - await CreateSecurityLog("Logout"); + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = IdentitySecurityLogActionConsts.Logout + }); + await SignInManager.SignOutAsync(); } @@ -133,7 +147,7 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers return new AbpLoginResult(LoginResultType.InvalidUserNameOrPassword); } - return new AbpLoginResult(LoginResultType.Success); + return new AbpLoginResult(LoginResultType.Succeeded); } protected virtual void ValidateLoginInfo(UserLoginInfo login) @@ -161,13 +175,5 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers throw new UserFriendlyException(L["LocalLoginDisabledMessage"]); } } - - protected virtual async Task CreateSecurityLog(string action) - { - var securityLog = await SecurityLogManager.CreateAsync(); - securityLog.Identity = "Web"; - securityLog.Action = action; - await SecurityLogManager.SaveAsync(securityLog); - } } } 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 d7fd0f8239..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,14 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; -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 Volo.Abp.SecurityLog; using IdentityUser = Volo.Abp.Identity.IdentityUser; namespace Volo.Abp.Account.Web.Pages.Account @@ -17,7 +15,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { public SignInManager SignInManager { get; set; } public IdentityUserManager UserManager { get; set; } - public ISecurityLogManager SecurityLogManager { get; } + public ILocalEventBus LocalEventBus { get; set; } protected AccountPageModel() { @@ -79,13 +77,5 @@ namespace Volo.Abp.Account.Web.Pages.Account { return "~/"; //TODO: ??? } - - protected virtual async Task CreateSecurityLog(string action) - { - var securityLog = await SecurityLogManager.CreateAsync(); - securityLog.Identity = "Web"; - securityLog.Action = action; - await SecurityLogManager.SaveAsync(securityLog); - } } } 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 2916e60b4f..06903ad44f 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.SecurityLog; using Volo.Abp.Settings; using Volo.Abp.Validation; using IdentityUser = Volo.Abp.Identity.IdentityUser; +using SignInResult = Microsoft.AspNetCore.Identity.SignInResult; namespace Volo.Abp.Account.Web.Pages.Account { @@ -95,7 +96,12 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); - await CreateSecurityLog(result.ToString()); + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = result.ToIdentitySecurityLogAction(), + UserName = LoginInput.UserNameOrEmailAddress + }); if (result.RequiresTwoFactor) { @@ -184,7 +190,14 @@ namespace Volo.Abp.Account.Web.Pages.Account bypassTwoFactor: true ); - await CreateSecurityLog(result.ToString()); + if (!result.Succeeded) + { + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, + Action = "Login" + result + }); + } if (result.IsLockedOut) { @@ -208,6 +221,15 @@ namespace Volo.Abp.Account.Web.Pages.Account var user = await CreateExternalUserAsync(info); await SignInManager.SignInAsync(user, false); + + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, + Action = result.ToIdentitySecurityLogAction(), + UserName = user.Name, + TenantId = user.TenantId + }); + 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..a9d4ed9a53 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 SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = IdentitySecurityLogActionConsts.Logout + }); + await SignInManager.SignOutAsync(); if (ReturnUrl != null) { 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/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/SecurityLogEvent.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs new file mode 100644 index 0000000000..d8857d02d9 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs @@ -0,0 +1,18 @@ +using System; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Identity +{ + public class SecurityLogEvent : 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; } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs new file mode 100644 index 0000000000..43321668b1 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs @@ -0,0 +1,85 @@ +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 SecurityLogHandler : ILocalEventHandler, ITransientDependency + { + protected ISecurityLogManager SecurityLogManager { get; } + protected IdentityUserManager UserManager { get; } + protected ICurrentPrincipalAccessor CurrentPrincipalAccessor { get; } + protected IUserClaimsPrincipalFactory UserClaimsPrincipalFactory { get; } + protected ICurrentUser CurrentUser { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } + + public SecurityLogHandler( + ISecurityLogManager securityLogManager, + IdentityUserManager userManager, + ICurrentPrincipalAccessor currentPrincipalAccessor, + IUserClaimsPrincipalFactory userClaimsPrincipalFactory, + ICurrentUser currentUser, + IUnitOfWorkManager unitOfWorkManager) + { + SecurityLogManager = securityLogManager; + UserManager = userManager; + CurrentPrincipalAccessor = currentPrincipalAccessor; + UserClaimsPrincipalFactory = userClaimsPrincipalFactory; + CurrentUser = currentUser; + UnitOfWorkManager = unitOfWorkManager; + } + + public async Task HandleEventAsync(SecurityLogEvent 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; + } + }; + + using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) + { + 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); + } + } + } + } + + await uow.CompleteAsync(); + } + } + } +} From 0466207a6d6545a51953a7b47d8270546c51c8f9 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:08:53 +0800 Subject: [PATCH 07/32] Implement security log in Identity module. --- .../SecurityLog/DefaultSecurityLogManager.cs | 2 +- .../Abp/SecurityLog/ISecurityLogManager.cs | 2 +- .../Volo/Abp/SecurityLog/SecurityLogInfo.cs | 2 +- .../Abp/Security/AbpSecurityTestModule.cs | 9 +- .../SecurityLog/SecurityLogManager_Tests.cs | 45 +++++++++ .../IdentityServerSupportedLoginModel.cs | 2 +- .../IdentityServerSupportedLogoutModel.cs | 7 ++ .../Account/Controllers/AccountController.cs | 6 +- .../Pages/Account/Login.cshtml.cs | 6 +- .../Pages/Account/Logout.cshtml.cs | 2 +- .../Abp/Identity/IdentitySecurityLogConsts.cs | 52 ++++++++++ .../IIdentitySecurityLogRepository.cs | 37 +++++++ .../Volo/Abp/Identity/IdentitySecurityLog.cs | 64 ++++++++++++ ...ogEvent.cs => IdentitySecurityLogEvent.cs} | 2 +- ...ndler.cs => IdentitySecurityLogHandler.cs} | 38 ++++--- .../Abp/Identity/IdentitySecurityLogStore.cs | 44 +++++++++ .../EFCoreIdentitySecurityLogRepository.cs | 98 ++++++++++++++++++ .../EntityFrameworkCore/IIdentityDbContext.cs | 3 + .../EntityFrameworkCore/IdentityDbContext.cs | 4 +- ...IdentityDbContextModelBuilderExtensions.cs | 28 +++++- .../MongoDB/AbpIdentityMongoDbContext.cs | 4 +- .../AbpIdentityMongoDbContextExtensions.cs | 7 +- .../MongoDB/AbpIdentityMongoDbModule.cs | 1 + .../MongoDB/IAbpIdentityMongoDbContext.cs | 4 +- .../MongoIdentitySecurityLogRepository.cs | 99 +++++++++++++++++++ .../IdentitySecurityLogRepository_Tests.cs | 7 ++ .../IdentitySecurityLogRepository_Tests.cs | 10 ++ .../Identity/AbpIdentityTestDataBuilder.cs | 36 ++++++- .../IdentitySecurityLogRepository_Tests.cs | 36 +++++++ 29 files changed, 615 insertions(+), 42 deletions(-) create mode 100644 framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/SecurityLog/SecurityLogManager_Tests.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogConsts.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLog.cs rename modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/{SecurityLogEvent.cs => IdentitySecurityLogEvent.cs} (84%) rename modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/{SecurityLogHandler.cs => IdentitySecurityLogHandler.cs} (67%) create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs create mode 100644 modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentitySecurityLogRepository_Tests.cs create mode 100644 modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentitySecurityLogRepository_Tests.cs create mode 100644 modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentitySecurityLogRepository_Tests.cs diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs index fcc03965f2..ab260ff708 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.SecurityLog SecurityLogOptions = securityLogOptions.Value; } - public async Task SaveAsync(Action saveAction) + public async Task SaveAsync(Action saveAction = null) { var securityLogInfo = await CreateAsync(); saveAction?.Invoke(securityLogInfo); diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs index 0bedfd0411..f368489fb0 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs @@ -5,6 +5,6 @@ namespace Volo.Abp.SecurityLog { public interface ISecurityLogManager { - Task SaveAsync(Action saveAction); + Task SaveAsync(Action saveAction = null); } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs index 6185777b97..e40b877fcf 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -5,7 +5,7 @@ using Volo.Abp.Data; namespace Volo.Abp.SecurityLog { [Serializable] - public class SecurityLogInfo : IHasExtraProperties + public class SecurityLogInfo { /// /// The name of the application or service writing user security logs. 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 0d90972792..d26e64181d 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 @@ -130,7 +130,7 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = result.ToIdentitySecurityLogAction(), 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 69b57a42f4..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 @@ -62,7 +62,7 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers true ); - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = signInResult.ToIdentitySecurityLogAction(), @@ -76,7 +76,7 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers [Route("logout")] public virtual async Task Logout() { - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = IdentitySecurityLogActionConsts.Logout @@ -147,7 +147,7 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers return new AbpLoginResult(LoginResultType.InvalidUserNameOrPassword); } - return new AbpLoginResult(LoginResultType.Succeeded); + return new AbpLoginResult(LoginResultType.Success); } protected virtual void ValidateLoginInfo(UserLoginInfo login) 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 06903ad44f..8dc2ef3273 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 @@ -96,7 +96,7 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = result.ToIdentitySecurityLogAction(), @@ -192,7 +192,7 @@ namespace Volo.Abp.Account.Web.Pages.Account if (!result.Succeeded) { - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, Action = "Login" + result @@ -222,7 +222,7 @@ namespace Volo.Abp.Account.Web.Pages.Account await SignInManager.SignInAsync(user, false); - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, Action = result.ToIdentitySecurityLogAction(), 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 a9d4ed9a53..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 @@ -16,7 +16,7 @@ namespace Volo.Abp.Account.Web.Pages.Account public virtual async Task OnGetAsync() { - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = IdentitySecurityLogActionConsts.Logout 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/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs new file mode 100644 index 0000000000..8732355c14 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs @@ -0,0 +1,37 @@ +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, + 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, + string userName = null, + string clientId = null, + string correlationId = null, + 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/SecurityLogEvent.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs similarity index 84% rename from modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs rename to modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs index d8857d02d9..93296619f6 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs @@ -3,7 +3,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.Identity { - public class SecurityLogEvent : IMultiTenant + public class IdentitySecurityLogEvent : IMultiTenant { public Guid? TenantId { get; set; } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs similarity index 67% rename from modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs rename to modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs index 43321668b1..4e0c46b2f7 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs @@ -10,32 +10,29 @@ using Volo.Abp.Users; namespace Volo.Abp.Identity { - public class SecurityLogHandler : ILocalEventHandler, ITransientDependency + 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; } - protected IUnitOfWorkManager UnitOfWorkManager { get; } - public SecurityLogHandler( + public IdentitySecurityLogHandler( ISecurityLogManager securityLogManager, IdentityUserManager userManager, ICurrentPrincipalAccessor currentPrincipalAccessor, IUserClaimsPrincipalFactory userClaimsPrincipalFactory, - ICurrentUser currentUser, - IUnitOfWorkManager unitOfWorkManager) + ICurrentUser currentUser) { SecurityLogManager = securityLogManager; UserManager = userManager; CurrentPrincipalAccessor = currentPrincipalAccessor; UserClaimsPrincipalFactory = userClaimsPrincipalFactory; CurrentUser = currentUser; - UnitOfWorkManager = unitOfWorkManager; } - public async Task HandleEventAsync(SecurityLogEvent eventData) + public async Task HandleEventAsync(IdentitySecurityLogEvent eventData) { Action securityLogAction = securityLog => { @@ -53,32 +50,31 @@ namespace Volo.Abp.Identity } }; - using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) + if (CurrentUser.IsAuthenticated) { - if (CurrentUser.IsAuthenticated) + await SecurityLogManager.SaveAsync(securityLogAction); + } + else + { + if (eventData.UserName.IsNullOrWhiteSpace()) { await SecurityLogManager.SaveAsync(securityLogAction); } else { - if (eventData.UserName.IsNullOrWhiteSpace()) + var user = await UserManager.FindByNameAsync(eventData.UserName); + if (user != null) { - await SecurityLogManager.SaveAsync(securityLogAction); + using (CurrentPrincipalAccessor.Change(await UserClaimsPrincipalFactory.CreateAsync(user))) + { + 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); - } - } + await SecurityLogManager.SaveAsync(securityLogAction); } } - - await uow.CompleteAsync(); } } } 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..696fc3ad6a --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs @@ -0,0 +1,44 @@ +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) + { + 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..1801a49136 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs @@ -0,0 +1,98 @@ +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, + string userName = null, + string clientId = null, + string correlationId = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + 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, + string userName = null, + string clientId = null, + string correlationId = null, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userName, + clientId, + correlationId + ); + + return await query.LongCountAsync(GetCancellationToken(cancellationToken)); + } + + protected virtual IQueryable GetListQuery( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = 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(!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..5fccb0d2ab --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs @@ -0,0 +1,99 @@ +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, + string userName = null, + string clientId = null, + string correlationId = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + 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, + string userName = null, + string clientId = null, + string correlationId = null, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userName, + clientId, + correlationId + ); + + return await query.As>().LongCountAsync(GetCancellationToken(cancellationToken)); + } + + protected virtual IQueryable GetListQuery( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = 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(!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); + } + } +} From 0c97d90c7d6eb49a3bb73332e5e69da123463eed Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:11:56 +0800 Subject: [PATCH 08/32] Update Volo.Abp.Security.csproj. --- framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj b/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj index 6ffaac1232..65aca85c88 100644 --- a/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj +++ b/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj @@ -16,7 +16,6 @@ - From a03ef9964151c6d455a8cf32a178dbf73fbc99c4 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:20:04 +0800 Subject: [PATCH 09/32] Update SecurityLogInfo. --- .../Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs index e40b877fcf..c6e562f6c8 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Volo.Abp.Data; namespace Volo.Abp.SecurityLog { From e931d2428d1fe6e20f91c4526416303bc9bb3b53 Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Thu, 9 Jul 2020 12:13:26 +0300 Subject: [PATCH 10/32] Update Microservice-Demo.md --- docs/en/Samples/Microservice-Demo.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/Samples/Microservice-Demo.md b/docs/en/Samples/Microservice-Demo.md index 30059a9379..7589c22958 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/). +* 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+). From 45e2b951d9ed72321b7dff621a88a97f0c5d6fe1 Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Thu, 9 Jul 2020 12:17:03 +0300 Subject: [PATCH 11/32] Update Microservice-Demo.md --- docs/en/Samples/Microservice-Demo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Samples/Microservice-Demo.md b/docs/en/Samples/Microservice-Demo.md index 7589c22958..9b4c622c4e 100644 --- a/docs/en/Samples/Microservice-Demo.md +++ b/docs/en/Samples/Microservice-Demo.md @@ -45,7 +45,7 @@ To be able to run the solution from source code, following tools should be insta ### 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/). +* 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. From 3199b5d0deef798f3f13a5bfabd1dd417300c155 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 9 Jul 2020 18:15:06 +0800 Subject: [PATCH 12/32] Use parameterInfo.Name when modelNameProvider.Name is null. --- .../Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 787a09546ff7cd9f32225d6f20ebe98449fe1bd4 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 10 Jul 2020 13:50:53 +0800 Subject: [PATCH 13/32] Add filter for IIdentitySecurityLogRepository. --- .../Pages/Account/Login.cshtml.cs | 3 +- .../IIdentitySecurityLogRepository.cs | 8 +++ .../Abp/Identity/IdentitySecurityLogEvent.cs | 15 +++++ .../Identity/IdentitySecurityLogHandler.cs | 5 ++ .../EFCoreIdentitySecurityLogRepository.cs | 13 +++- .../MongoIdentitySecurityLogRepository.cs | 62 ++++++++++++------- 6 files changed, 81 insertions(+), 25 deletions(-) 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 8dc2ef3273..ca2125396c 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 @@ -226,8 +226,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, Action = result.ToIdentitySecurityLogAction(), - UserName = user.Name, - TenantId = user.TenantId + UserName = user.Name }); return RedirectSafely(returnUrl, returnUrlHash); 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 index 8732355c14..f68f289b4f 100644 --- 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 @@ -17,6 +17,7 @@ namespace Volo.Abp.Identity string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -29,9 +30,16 @@ namespace Volo.Abp.Identity 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/IdentitySecurityLogEvent.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs index 93296619f6..faac2d5033 100644 --- 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 @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Volo.Abp.MultiTenancy; namespace Volo.Abp.Identity @@ -14,5 +15,19 @@ namespace Volo.Abp.Identity 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 index 4e0c46b2f7..5000d4d288 100644 --- 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 @@ -48,6 +48,11 @@ namespace Volo.Abp.Identity { securityLog.ClientId = eventData.ClientId; } + + foreach (var property in eventData.ExtraProperties) + { + securityLog.ExtraProperties[property.Key] = property.Value; + } }; if (CurrentUser.IsAuthenticated) 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 index 1801a49136..137341a25e 100644 --- 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 @@ -27,6 +27,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -39,6 +40,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore applicationName, identity, action, + userId, userName, clientId, correlationId @@ -55,6 +57,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -66,6 +69,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore applicationName, identity, action, + userId, userName, clientId, correlationId @@ -74,12 +78,18 @@ namespace Volo.Abp.Identity.EntityFrameworkCore return await query.LongCountAsync(GetCancellationToken(cancellationToken)); } - protected virtual IQueryable GetListQuery( + 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) @@ -90,6 +100,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .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.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs index 5fccb0d2ab..4336abaaae 100644 --- 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 @@ -11,7 +11,8 @@ using Volo.Abp.MongoDB; namespace Volo.Abp.Identity.MongoDB { - public class MongoIdentitySecurityLogRepository : MongoDbRepository, IIdentitySecurityLogRepository + public class MongoIdentitySecurityLogRepository : + MongoDbRepository, IIdentitySecurityLogRepository { public MongoIdentitySecurityLogRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) @@ -27,6 +28,7 @@ namespace Volo.Abp.Identity.MongoDB string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -39,6 +41,7 @@ namespace Volo.Abp.Identity.MongoDB applicationName, identity, action, + userId, userName, clientId, correlationId @@ -56,6 +59,7 @@ namespace Volo.Abp.Identity.MongoDB string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -67,33 +71,47 @@ namespace Volo.Abp.Identity.MongoDB applicationName, identity, action, + userId, userName, clientId, correlationId ); - return await query.As>().LongCountAsync(GetCancellationToken(cancellationToken)); + return await query.As>() + .LongCountAsync(GetCancellationToken(cancellationToken)); } - protected virtual IQueryable GetListQuery( - DateTime? startTime = null, - DateTime? endTime = null, - string applicationName = null, - string identity = null, - string action = 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(!userName.IsNullOrWhiteSpace(), securityLog => securityLog.UserName == userName) - .WhereIf(!clientId.IsNullOrWhiteSpace(), securityLog => securityLog.ClientId == clientId) - .WhereIf(!correlationId.IsNullOrWhiteSpace(), securityLog => securityLog.CorrelationId == correlationId); - } + + 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); + } } } From 37508abfa22c17ce661edf8feb40a3fa0103c7cf Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 10 Jul 2020 14:51:34 +0800 Subject: [PATCH 14/32] Update template projects migrations. --- .../20200710064926_Initial.Designer.cs} | 168 +++++++++++++++++- .../Migrations/20200710064926_Initial.cs} | 100 +++++++++++ ...ectNameMigrationsDbContextModelSnapshot.cs | 75 ++++++++ .../20200710065039_Initial.Designer.cs} | 168 ++++++++---------- .../Migrations/20200710065039_Initial.cs} | 100 +++++------ ...verHostMigrationsDbContextModelSnapshot.cs | 75 ++++++++ ....cs => 20200710065052_Initial.Designer.cs} | 77 +++++++- ...0_Initial.cs => 20200710065052_Initial.cs} | 48 +++++ .../UnifiedDbContextModelSnapshot.cs | 75 ++++++++ 9 files changed, 740 insertions(+), 146 deletions(-) rename templates/{module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.Designer.cs => app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.Designer.cs} (92%) rename templates/{module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.cs => app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.cs} (91%) rename templates/{app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.Designer.cs => module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs} (96%) rename templates/{app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.cs => module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs} (96%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/{20200624023340_Initial.Designer.cs => 20200710065052_Initial.Designer.cs} (93%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/{20200624023340_Initial.cs => 20200710065052_Initial.cs} (92%) 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") From 40dc60cb6cb41bb80d33b54c6d21fcadde837e85 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 10 Jul 2020 15:31:14 +0800 Subject: [PATCH 15/32] Disable Security Log feature. --- .../SecurityLog/AspNetCoreSecurityLogManager.cs | 1 - .../Abp/SecurityLog/DefaultSecurityLogManager.cs | 5 +++++ .../Volo/Abp/SecurityLog/SecurityLogInfo.cs | 10 ---------- .../Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs | 12 ++++++++++-- .../Volo/Abp/Identity/IdentitySecurityLogStore.cs | 5 +++++ 5 files changed, 20 insertions(+), 13 deletions(-) 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 index 55ece86be2..f0fc0aa347 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs @@ -23,7 +23,6 @@ namespace Volo.Abp.AspNetCore.SecurityLog protected ICurrentClient CurrentClient { get; } protected IHttpContextAccessor HttpContextAccessor { get; } protected ICorrelationIdProvider CorrelationIdProvider { get; } - protected IWebClientInfoProvider WebClientInfoProvider { get; } public AspNetCoreSecurityLogManager( diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs index ab260ff708..f628958bc4 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs @@ -21,6 +21,11 @@ namespace Volo.Abp.SecurityLog public async Task SaveAsync(Action saveAction = null) { + if (!SecurityLogOptions.IsEnabled) + { + return; + } + var securityLogInfo = await CreateAsync(); saveAction?.Invoke(securityLogInfo); await SecurityLogStore.SaveAsync(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 index c6e562f6c8..b187b5bfa2 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -6,20 +6,10 @@ namespace Volo.Abp.SecurityLog [Serializable] public class SecurityLogInfo { - /// - /// The name of the application or service writing user security logs. - /// Default: null. - /// public string ApplicationName { get; set; } - /// - /// Web, JWT, Identity, Identity_Server - /// public string Identity { get; set; } - /// - /// login_successful, login_failed, logout, change_pwd, refresh_token... - /// public string Action { get; set; } public Dictionary ExtraProperties { get; } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs index bc9c22c4df..fe6496ef40 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; namespace Volo.Abp.SecurityLog @@ -7,16 +8,23 @@ namespace Volo.Abp.SecurityLog public class SimpleSecurityLogStore : ISecurityLogStore, ITransientDependency { public ILogger Logger { get; set; } + protected AbpSecurityLogOptions SecurityLogOptions { get; } - public SimpleSecurityLogStore(ILogger logger) + 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.FromResult(0); + return Task.CompletedTask; } } } 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 index 696fc3ad6a..17e3c20794 100644 --- 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 @@ -34,6 +34,11 @@ namespace Volo.Abp.Identity public async Task SaveAsync(SecurityLogInfo securityLogInfo) { + if (!SecurityLogOptions.IsEnabled) + { + return; + } + using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) { await IdentitySecurityLogRepository.InsertAsync(new IdentitySecurityLog(GuidGenerator, securityLogInfo)); From ef3cab9b08d63ca64269afaae756cd044a3542fc Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 10 Jul 2020 17:19:01 +0800 Subject: [PATCH 16/32] Refatoring BundleContributor Make it support LocalizationMapOptions Resolve #4574 --- .../AbpAspNetCoreMvcUiPackagesModule.cs | 13 ++++++ .../BootstrapDatepickerScriptContributor.cs | 21 ++-------- .../JQueryValidationScriptContributor.cs | 40 ++----------------- .../Timeago/TimeagoScriptContributor.cs | 18 ++++----- .../AbpLocalizationOptionsExtensions.cs | 11 +++++ 5 files changed, 38 insertions(+), 65 deletions(-) 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..89705f8959 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.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)) From 0077d159ff5f17d4cb957e57103b78792788aee8 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 10 Jul 2020 17:38:30 +0800 Subject: [PATCH 17/32] fix language typo. --- .../Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 89705f8959..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 @@ -25,8 +25,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages //Timeago options.AddLanguageFilesMapOrUpdate(TimeagoScriptContributor.PackageName, - new NameValue("zh-Hans", "zh_CN"), - new NameValue("zh-Hant", "zh_TW")); + new NameValue("zh-Hans", "zh-CN"), + new NameValue("zh-Hant", "zh-TW")); //JQueryValidation options.AddLanguageFilesMapOrUpdate(JQueryValidationScriptContributor.PackageName, From 1a06410befb2c011bde681f23b0c8a3246cdf0d5 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 13 Jul 2020 08:47:32 +0800 Subject: [PATCH 18/32] Do nothing if there is no renderer registered with the given name. --- .../datatables/datatables-extensions.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 dd749d0bc1..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,9 +299,11 @@ column.targets = i; } - if (!column.render && column.dataFormat){ + if (!column.render && column.dataFormat) { var render = datatables.defaultRenderers[column.dataFormat]; - column.render = render ? render : ISOStringToDateTimeLocaleString(column.dataFormat); + if (render) { + column.render = render; + } } if (column.rowAction) { From 71331f47cf602901639444ae50096cd196772d1f Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 17 Jul 2020 10:10:06 +0800 Subject: [PATCH 19/32] Move cancel button to the form & add formnovalidate attribute. --- .../Volo.Abp.Account.Web/Pages/Account/Login.cshtml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) 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) - { - - } } From ca9b36046c93a52786ac646267e7e229679d1de1 Mon Sep 17 00:00:00 2001 From: "nuck.tang" Date: Fri, 17 Jul 2020 17:47:21 +0800 Subject: [PATCH 20/32] Add minio document --- docs/en/Blob-Storing-Minio.md | 66 ++++++++++++++++++++++++++++++ docs/zh-Hans/Blob-Storing-Minio.md | 66 ++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 docs/en/Blob-Storing-Minio.md create mode 100644 docs/zh-Hans/Blob-Storing-Minio.md 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/zh-Hans/Blob-Storing-Minio.md b/docs/zh-Hans/Blob-Storing-Minio.md new file mode 100644 index 0000000000..73848972f7 --- /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`. 如果你想自定义文件路径计算,可以替换/覆盖它. From a9863a2a8f3dab59202529b56200f75fd0554c15 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Fri, 17 Jul 2020 18:54:26 +0800 Subject: [PATCH 21/32] Update blob document --- docs/en/Blob-Storing.md | 2 ++ docs/en/docs-nav.json | 4 +++ docs/zh-Hans/Blob-Storing-Minio.md | 42 +++++++++++++++--------------- docs/zh-Hans/Blob-Storing.md | 2 ++ docs/zh-Hans/docs-nav.json | 4 +++ 5 files changed, 33 insertions(+), 21 deletions(-) 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/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 index 73848972f7..f7c0b25771 100644 --- a/docs/zh-Hans/Blob-Storing-Minio.md +++ b/docs/zh-Hans/Blob-Storing-Minio.md @@ -1,22 +1,22 @@ # BLOB Storing Minio 提供程序 -BLOB Storing Minio提供程序帮助你存储对象到 [MinIO Object storage](https://min.io/)。 +BLOB Storing Minio提供程序帮助你存储对象到 [MinIO Object storage](https://min.io/), -> 阅读[BLOB存储文档](Blob-Storing.md)了解如何使用BLOB存储系统。 本文档仅介绍如何为容器配置Minio提供程序。 +> 阅读[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` 命令。 +* 如果你没有安装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) 类上。 +如果你要手动安装, 通过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`方法中完成。 +配置在你的[module](Module-Development-Basics.md)类中的`ConfigureServices`方法中完成, **例: 配置使用Minio存储** @@ -33,32 +33,32 @@ Configure(options => }); ```` -> 参阅[BLOB存储文档](Blob-Storing.md) 学习如何为指定容器配置提供程序。 +> 参阅[BLOB存储文档](Blob-Storing.md) 学习如何为指定容器配置提供程序, ### 选项 -* **EndPoint** (string): 你的Minio对象存储服务的URL。 查看文档:https://docs.min.io/docs/dotnet-client-quickstart-guide.html -* **AccessKey** (string): Access key是唯一标识你的账户的用户ID。 +* **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): +* **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名字必须是 **小写** 的字母,数字,点号(.), 横杠 (-), + * Bucket名字必须是以数字和字母开头和结尾, + * Bucket名字不能是ip (例如, 192.168.5.4), + * Bucket名字不能以 **xn--** 开头, (2020年2月以后创建), * Bucket名字必须区块唯一 - * Buckets如果使用Amazon S3加速传输名字不能有点号(.)。 -* **WithSSL** (bool): 默认 `false`,代表使用HTTPS。 -* **CreateContainerIfNotExists** (bool): 默认 `false`,如果不存在bucket, `MinioBlobProvider` 将会创建一个。 + * Buckets如果使用Amazon S3加速传输名字不能有点号(.), +* **WithSSL** (bool): 默认 `false`,代表使用HTTPS, +* **CreateContainerIfNotExists** (bool): 默认 `false`,如果不存在bucket, `MinioBlobProvider` 将会创建一个, ## Minio BLOB 名称计算器 默认情况下BLOB的全名由以下规则确定: -* 如果当前租户为 `null`(或容器禁用多租户 - 请参阅[BLOB存储文档](Blob-Storing.md) 了解如何禁用容器的多租户),则追加 `host` 字符串。 -* 如果当前租户不为 `null`,则追加 `tenants/` 字符串。 -* 追加 BLOB 名称。 +* 如果当前租户为 `null`(或容器禁用多租户 - 请参阅[BLOB存储文档](Blob-Storing.md) 了解如何禁用容器的多租户),则追加 `host` 字符串, +* 如果当前租户不为 `null`,则追加 `tenants/` 字符串, +* 追加 BLOB 名称, ## 其他服务 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" From bed0efa9b958b27ace924b844039360d162c69ad Mon Sep 17 00:00:00 2001 From: Erol Arkat Date: Fri, 17 Jul 2020 14:30:47 +0300 Subject: [PATCH 22/32] npm preview myget url update --- npm/ng-packs/scripts/publish.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 { From f4dad58d83c11ce1d5bdbbf46e66de11c02fd565 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Jul 2020 14:51:46 +0300 Subject: [PATCH 23/32] feat(components/tree): add draggable ability to tree component --- .../tree/src/lib/components/tree.component.html | 2 ++ .../tree/src/lib/components/tree.component.ts | 10 ++++++++++ 2 files changed, 12 insertions(+) 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..019c2bd0fa 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,5 @@
(); @Output() readonly selectedNodeChange = new EventEmitter(); + @Output() readonly drop = new EventEmitter(); + @Input() draggable: boolean; @Input() checkable: boolean; @Input() checkStrictly: boolean; @Input() checkedKeys = []; @@ -44,4 +47,11 @@ export class TreeComponent { this.expandedKeys = [...event.keys]; this.expandedKeysChange.emit(event.keys); } + + onDrop(event: NzFormatEmitEvent) { + event.event.stopPropagation(); + event.event.preventDefault(); + + this.drop.emit(event); + } } From ac80704a7405441f6ffa600ab1452f3770c09649 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Jul 2020 14:51:57 +0300 Subject: [PATCH 24/32] ci: add @abp/ng.components to build script --- npm/ng-packs/scripts/build.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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: '../' }, ); From 380586ac7fe5077e09f6523e4d10dc7258d19673 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Jul 2020 15:46:45 +0300 Subject: [PATCH 25/32] fix: linter warnings --- .../account/src/lib/tests/account.service.spec.ts | 4 ++-- .../packages/core/src/lib/tests/api.interceptor.spec.ts | 4 ++-- .../lib/tests/application-configuration.service.spec.ts | 2 +- .../packages/core/src/lib/tests/auth.guard.spec.ts | 6 +++--- .../core/src/lib/tests/config-state.service.spec.ts | 2 +- .../packages/core/src/lib/tests/config.state.spec.ts | 6 +++--- .../core/src/lib/tests/dynamic-layout.component.spec.ts | 4 ++-- .../packages/core/src/lib/tests/locale.provider.spec.ts | 6 +++--- .../core/src/lib/tests/localization.pipe.spec.ts | 4 ++-- .../core/src/lib/tests/localization.service.spec.ts | 4 ++-- .../core/src/lib/tests/permission.directive.spec.ts | 2 +- .../packages/core/src/lib/tests/permission.guard.spec.ts | 2 +- .../core/src/lib/tests/profile-state.service.spec.ts | 2 +- .../packages/core/src/lib/tests/profile.service.spec.ts | 6 +++--- .../packages/core/src/lib/tests/profile.state.spec.ts | 2 +- .../src/lib/tests/replaceable-components.state.spec.ts | 6 +++--- .../packages/core/src/lib/tests/rest.service.spec.ts | 2 +- .../core/src/lib/tests/session-state.service.spec.ts | 2 +- .../lib/tests/feature-management-state.service.spec.ts | 2 +- .../src/lib/tests/identity-state.service.spec.ts | 2 +- .../tests/permission-management-state.service.spec.ts | 2 +- .../lib/tests/tenant-management-state.service.spec.ts | 2 +- .../extensions/src/tests/form-props.util.spec.ts | 4 ++-- .../src/lib/tests/append-content.token.spec.ts | 6 +++--- .../src/lib/tests/breadcrumb.component.spec.ts | 4 ++-- .../theme-shared/src/lib/tests/error.handler.spec.ts | 6 +++--- .../src/lib/tests/loader-bar.component.spec.ts | 8 ++++---- .../src/lib/tests/modal-container.component.spec.ts | 2 +- .../theme-shared/src/lib/tests/modal.component.spec.ts | 4 ++-- .../theme-shared/src/lib/tests/validation-utils.spec.ts | 2 +- npm/ng-packs/yarn.lock | 9 ++++++++- 31 files changed, 63 insertions(+), 56 deletions(-) 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/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/yarn.lock b/npm/ng-packs/yarn.lock index 6c27814650..fcdca8c3c7 100644 --- a/npm/ng-packs/yarn.lock +++ b/npm/ng-packs/yarn.lock @@ -2319,13 +2319,20 @@ rxjs "6.5.5" webpack-sources "1.4.3" -"@ngx-validate/core@^0.0.8", "@ngx-validate/core@^0.0.9": +"@ngx-validate/core@^0.0.8": 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== dependencies: tslib "^1.9.0" +"@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" + "@ngxs/devtools-plugin@^3.6.2": version "3.6.2" resolved "https://registry.yarnpkg.com/@ngxs/devtools-plugin/-/devtools-plugin-3.6.2.tgz#aa0a4835f90fb905951d7712dc3ce508cbc15a2c" From e8ec2816e2f4690f97cc570dd4ef3d0b49eb4122 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Jul 2020 15:47:14 +0300 Subject: [PATCH 26/32] feat(components/tree): add an input named beforeDrop --- .../components/tree/src/lib/components/tree.component.html | 1 + .../components/tree/src/lib/components/tree.component.ts | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) 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 019c2bd0fa..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,5 @@ (); @Output() readonly selectedNodeChange = new EventEmitter(); - @Output() readonly drop = new EventEmitter(); + @Output() readonly dropOver = new EventEmitter(); @Input() draggable: boolean; @Input() checkable: boolean; @Input() checkStrictly: boolean; @@ -32,6 +33,7 @@ export class TreeComponent { @Input() expandedKeys: string[] = []; @Input() selectedNode: any; @Input() isNodeSelected = node => this.selectedNode?.id === node.key; + @Input() beforeDrop = () => of(false); onSelectedNodeChange(node) { this.selectedNode = node.origin.entity; @@ -52,6 +54,6 @@ export class TreeComponent { event.event.stopPropagation(); event.event.preventDefault(); - this.drop.emit(event); + this.dropOver.emit(event); } } From a998df79c8a4e6eacb840227f1840912359d4860 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Jul 2020 16:33:02 +0300 Subject: [PATCH 27/32] feat(components/tree): add drop position to drop event --- .../tree/src/lib/components/tree.component.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts index 5c39c47057..a3d2368dac 100644 --- a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts +++ b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts @@ -7,9 +7,11 @@ import { TemplateRef, ViewEncapsulation, } from '@angular/core'; -import { NzFormatEmitEvent } from 'ng-zorro-antd/tree'; +import { NzFormatEmitEvent, NzFormatBeforeDropEvent } from 'ng-zorro-antd/tree'; import { of } from 'rxjs'; +export type DropEvent = NzFormatEmitEvent & { pos: -1 | 0 | 1 }; + @Component({ selector: 'abp-tree', templateUrl: 'tree.component.html', @@ -20,11 +22,13 @@ import { of } from 'rxjs'; encapsulation: ViewEncapsulation.None, }) export class TreeComponent { + dropPosition: -1 | 0 | 1; + @ContentChild('menu') menu: TemplateRef; @Output() readonly checkedKeysChange = new EventEmitter(); @Output() readonly expandedKeysChange = new EventEmitter(); @Output() readonly selectedNodeChange = new EventEmitter(); - @Output() readonly dropOver = new EventEmitter(); + @Output() readonly dropOver = new EventEmitter(); @Input() draggable: boolean; @Input() checkable: boolean; @Input() checkStrictly: boolean; @@ -33,7 +37,10 @@ export class TreeComponent { @Input() expandedKeys: string[] = []; @Input() selectedNode: any; @Input() isNodeSelected = node => this.selectedNode?.id === node.key; - @Input() beforeDrop = () => of(false); + @Input() beforeDrop = (event: NzFormatBeforeDropEvent) => { + this.dropPosition = event.pos; + return of(false); + }; onSelectedNodeChange(node) { this.selectedNode = node.origin.entity; @@ -50,9 +57,10 @@ export class TreeComponent { this.expandedKeysChange.emit(event.keys); } - onDrop(event: NzFormatEmitEvent) { + onDrop(event: DropEvent) { event.event.stopPropagation(); event.event.preventDefault(); + event.pos = this.dropPosition; this.dropOver.emit(event); } From b7dd3f8e30adf0aa730e0d9821825959e74ad3bc Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Jul 2020 16:34:30 +0300 Subject: [PATCH 28/32] fix: a type error --- .../components/tree/src/lib/components/tree.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts index a3d2368dac..ac7a709048 100644 --- a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts +++ b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts @@ -10,7 +10,7 @@ import { import { NzFormatEmitEvent, NzFormatBeforeDropEvent } from 'ng-zorro-antd/tree'; import { of } from 'rxjs'; -export type DropEvent = NzFormatEmitEvent & { pos: -1 | 0 | 1 }; +export type DropEvent = NzFormatEmitEvent & { pos: number }; @Component({ selector: 'abp-tree', @@ -22,7 +22,7 @@ export type DropEvent = NzFormatEmitEvent & { pos: -1 | 0 | 1 }; encapsulation: ViewEncapsulation.None, }) export class TreeComponent { - dropPosition: -1 | 0 | 1; + dropPosition: number; @ContentChild('menu') menu: TemplateRef; @Output() readonly checkedKeysChange = new EventEmitter(); From 18c80d88da882908469e45e66579ec5f730ead3a Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Jul 2020 17:20:04 +0300 Subject: [PATCH 29/32] chore: remove @ngx-validate/core from resolutions --- npm/ng-packs/package.json | 3 -- npm/ng-packs/yarn.lock | 93 +++++++++++++++++++++------------------ 2 files changed, 49 insertions(+), 47 deletions(-) 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/yarn.lock b/npm/ng-packs/yarn.lock index fcdca8c3c7..c94fdbb1bc 100644 --- a/npm/ng-packs/yarn.lock +++ b/npm/ng-packs/yarn.lock @@ -2319,13 +2319,6 @@ rxjs "6.5.5" webpack-sources "1.4.3" -"@ngx-validate/core@^0.0.8": - 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== - dependencies: - tslib "^1.9.0" - "@ngx-validate/core@^0.0.9": version "0.0.9" resolved "https://registry.yarnpkg.com/@ngx-validate/core/-/core-0.0.9.tgz#c5baea9e6f2f28c70d1adaf1edde5a9bcc8929c0" @@ -2409,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" @@ -2461,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" @@ -2472,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" @@ -2586,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" @@ -4123,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" @@ -5704,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" @@ -8590,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: @@ -9298,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== @@ -12648,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== @@ -12662,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" @@ -13069,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" @@ -13104,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" @@ -13234,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" @@ -13333,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" From beadedc0c69cc060b577797d7087b1c4b2f8cdcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 17 Jul 2020 17:26:22 +0300 Subject: [PATCH 30/32] Introduce the IEventDataMayHaveTenantId interface. --- .../Events/Distributed/EntityCreatedEto.cs | 15 +++++++++- .../Events/Distributed/EntityDeletedEto.cs | 17 +++++++++-- .../Events/Distributed/EntityUpdatedEto.cs | 17 +++++++++-- .../Domain/Entities/Events/EntityEventData.cs | 17 +++++++++-- .../Abp/EventBus/IEventDataMayHaveTenantId.cs | 28 +++++++++++++++++++ 5 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventDataMayHaveTenantId.cs 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.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); + } +} From b9d262b318e90deb2972952187d80edc46eb3008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 17 Jul 2020 18:14:06 +0300 Subject: [PATCH 31/32] Use WidgetManager for the cms reaction --- .../ReactionSelection/Default.cshtml | 4 +- .../ReactionSelectionViewComponent.cs | 1 + .../Components/ReactionSelection/default.js | 60 +++++++++++++------ 3 files changed, 45 insertions(+), 20 deletions(-) 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..298ab57c66 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,49 @@ -(function () { +(function ($) { $(document).ready(function () { - function initReactionSelection() { - var $wrapper = $(this); - var $availableReactions = $wrapper.find('.cms-reaction-selection-available-reactions'); - - $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 !!!!!!!! + abp.widgets.CmsReactionSelection= function ($widget) { + + var getFilters = function () { + return { + + }; + } + + var refresh = function (filters) { + + }; + + var init = function (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 () { + location.reload(); //TODO: JUST TESTING !!!!!!!! + }); }); }); + }; + + return { + getFilters: getFilters, + init: init, + refresh: refresh + }; + }; + + $('.abp-widget-wrapper[data-widget-name="CmsReactionSelection"]').each(function(){ + var $widget = $(this); + var widgetManager = new abp.WidgetManager({ + wrapper: $widget.parent(), //TODO: Change to $widget once WidgetManager supports it! }); - } - $('.cms-reaction-selection').each(initReactionSelection); + widgetManager.init(); + }); }); -})(); +})(jQuery); From 9c70d7c3935af142ba23c21a54e73c6f5c915238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 17 Jul 2020 18:27:41 +0300 Subject: [PATCH 32/32] widget-manager should use findWithSelf --- .../jquery/widget-manager.js | 8 ++--- .../Components/ReactionSelection/default.js | 29 +++++++++---------- 2 files changed, 17 insertions(+), 20 deletions(-) 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/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 298ab57c66..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,19 +1,17 @@ (function ($) { $(document).ready(function () { - abp.widgets.CmsReactionSelection= function ($widget) { + abp.widgets.CmsReactionSelection = function ($widget) { - var getFilters = function () { - return { - - }; + function getFilters() { + return {}; } - var refresh = function (filters) { - - }; + function refresh(filters) { + location.reload(); //TODO: JUST TESTING !!!!!!!! + } - var init = function (filters) { + function init(filters) { var $wrapper = $widget.find('.cms-reaction-selection'); $widget.find('.cms-reaction-icon').each(function () { var $icon = $(this); @@ -24,23 +22,22 @@ entityId: $wrapper.attr('data-entity-id'), reactionName: $icon.attr('data-name') }).then(function () { - location.reload(); //TODO: JUST TESTING !!!!!!!! + refresh(); }); }); }); - }; + } return { - getFilters: getFilters, init: init, - refresh: refresh + refresh: refresh, + getFilters : getFilters }; }; - $('.abp-widget-wrapper[data-widget-name="CmsReactionSelection"]').each(function(){ - var $widget = $(this); + $('.abp-widget-wrapper[data-widget-name="CmsReactionSelection"]').each(function () { var widgetManager = new abp.WidgetManager({ - wrapper: $widget.parent(), //TODO: Change to $widget once WidgetManager supports it! + wrapper: $(this), }); widgetManager.init();