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 001/376] 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 f8a251afb9a9549be185279bc5ecad4c100b2467 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 29 Jun 2020 16:20:24 +0800 Subject: [PATCH 002/376] Storage cache in the unit of work. Resolve #4040 --- .../Volo/Abp/Caching/AbpCachingModule.cs | 2 + .../Volo/Abp/Caching/DistributedCache.cs | 546 ++++++++++++++---- .../Volo/Abp/Caching/IDistributedCache.cs | 34 +- .../Volo/Abp/Caching/UnitOfWorkCacheItem.cs | 43 ++ .../Caching/UnitOfWorkCacheItemExtensions.cs | 11 + .../Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs | 4 +- .../Volo/Abp/Uow/UnitOfWorkExtensions.cs | 45 +- .../Abp/Caching/DistributedCache_Tests.cs | 244 +++++++- .../FeatureManagementStore.cs | 29 +- .../FeatureManagementStore_Tests.cs | 51 ++ .../SettingManagementStore.cs | 31 +- .../SettingManagementStore_Tests.cs | 34 ++ 12 files changed, 924 insertions(+), 150 deletions(-) create mode 100644 framework/src/Volo.Abp.Caching/Volo/Abp/Caching/UnitOfWorkCacheItem.cs create mode 100644 framework/src/Volo.Abp.Caching/Volo/Abp/Caching/UnitOfWorkCacheItemExtensions.cs diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs index ba59bf039e..d133ac110b 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs @@ -5,12 +5,14 @@ using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; using Volo.Abp.Serialization; using Volo.Abp.Threading; +using Volo.Abp.Uow; namespace Volo.Abp.Caching { [DependsOn( typeof(AbpThreadingModule), typeof(AbpSerializationModule), + typeof(AbpUnitOfWorkModule), typeof(AbpMultiTenancyModule), typeof(AbpJsonModule))] public class AbpCachingModule : AbpModule diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs index 5bb1dd2481..28082832b0 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs @@ -14,6 +14,7 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.ExceptionHandling; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; +using Volo.Abp.Uow; namespace Volo.Abp.Caching { @@ -30,13 +31,15 @@ namespace Volo.Abp.Caching ICancellationTokenProvider cancellationTokenProvider, IDistributedCacheSerializer serializer, IDistributedCacheKeyNormalizer keyNormalizer, - IHybridServiceScopeFactory serviceScopeFactory) : base( - distributedCacheOption: distributedCacheOption, - cache: cache, - cancellationTokenProvider: cancellationTokenProvider, - serializer: serializer, - keyNormalizer: keyNormalizer, - serviceScopeFactory: serviceScopeFactory) + IHybridServiceScopeFactory serviceScopeFactory, + IUnitOfWorkManager unitOfWorkManager) : base( + distributedCacheOption: distributedCacheOption, + cache: cache, + cancellationTokenProvider: cancellationTokenProvider, + serializer: serializer, + keyNormalizer: keyNormalizer, + serviceScopeFactory: serviceScopeFactory, + unitOfWorkManager:unitOfWorkManager) { } } @@ -50,6 +53,8 @@ namespace Volo.Abp.Caching public class DistributedCache : IDistributedCache where TCacheItem : class { + public const string DistributedCacheName = "AbpDistributedCache"; + public ILogger> Logger { get; set; } protected string CacheName { get; set; } @@ -66,6 +71,8 @@ namespace Volo.Abp.Caching protected IHybridServiceScopeFactory ServiceScopeFactory { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } + protected SemaphoreSlim SyncSemaphore { get; } protected DistributedCacheEntryOptions DefaultCacheOptions; @@ -78,7 +85,8 @@ namespace Volo.Abp.Caching ICancellationTokenProvider cancellationTokenProvider, IDistributedCacheSerializer serializer, IDistributedCacheKeyNormalizer keyNormalizer, - IHybridServiceScopeFactory serviceScopeFactory) + IHybridServiceScopeFactory serviceScopeFactory, + IUnitOfWorkManager unitOfWorkManager) { _distributedCacheOption = distributedCacheOption.Value; Cache = cache; @@ -87,6 +95,7 @@ namespace Volo.Abp.Caching Serializer = serializer; KeyNormalizer = keyNormalizer; ServiceScopeFactory = serviceScopeFactory; + UnitOfWorkManager = unitOfWorkManager; SyncSemaphore = new SemaphoreSlim(1, 1); @@ -133,14 +142,25 @@ namespace Volo.Abp.Caching /// Gets a cache item with the given key. If no cache item is found for the given key then returns null. /// /// The key of cached item to be retrieved from the cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The cache item, or null. public virtual TCacheItem Get( TCacheKey key, + bool considerUow = false, bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + if (ShouldConsiderUow(considerUow)) + { + var value = GetUnitOfWorkCache().GetOrDefault(key)?.GetUnRemovedValueOrNull(); + if (value != null) + { + return value; + } + } + byte[] cachedBytes; try @@ -163,6 +183,7 @@ namespace Volo.Abp.Caching public virtual KeyValuePair[] GetMany( IEnumerable keys, + bool considerUow = false, bool? hideErrors = null) { var keyArray = keys.ToArray(); @@ -172,33 +193,57 @@ namespace Volo.Abp.Caching { return GetManyFallback( keyArray, + considerUow, hideErrors ); } + var cachedValues = new List>(); + var notCachedKeys = new List(); + if (ShouldConsiderUow(considerUow)) + { + var cache = GetUnitOfWorkCache(); + foreach (var key in keyArray) + { + var value = cache.GetOrDefault(key)?.GetUnRemovedValueOrNull(); + if (value != null) + { + cachedValues.Add(new KeyValuePair(key, value)); + } + } + + notCachedKeys = keyArray.Except(cachedValues.Select(x => x.Key)).ToList(); + if (!notCachedKeys.Any()) + { + return cachedValues.ToArray(); + } + } + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; byte[][] cachedBytes; + var readKeys = notCachedKeys.Any() ? notCachedKeys.ToArray() : keyArray; try { - cachedBytes = cacheSupportsMultipleItems.GetMany(keyArray.Select(NormalizeKey)); + cachedBytes = cacheSupportsMultipleItems.GetMany(readKeys.Select(NormalizeKey)); } catch (Exception ex) { if (hideErrors == true) { HandleException(ex); - return ToCacheItemsWithDefaultValues(keyArray); + return ToCacheItemsWithDefaultValues(readKeys); } throw; } - - return ToCacheItems(cachedBytes, keyArray); + + return cachedValues.Concat(ToCacheItems(cachedBytes, readKeys)).ToArray(); } protected virtual KeyValuePair[] GetManyFallback( TCacheKey[] keys, + bool considerUow = false, bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -208,7 +253,7 @@ namespace Volo.Abp.Caching return keys .Select(key => new KeyValuePair( key, - Get(key, hideErrors: false) + Get(key, considerUow, hideErrors: false) ) ).ToArray(); } @@ -226,6 +271,7 @@ namespace Volo.Abp.Caching public virtual async Task[]> GetManyAsync( IEnumerable keys, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default) { @@ -236,18 +282,42 @@ namespace Volo.Abp.Caching { return await GetManyFallbackAsync( keyArray, + considerUow, hideErrors, token ); } + var cachedValues = new List>(); + var notCachedKeys = new List(); + if (ShouldConsiderUow(considerUow)) + { + var cache = GetUnitOfWorkCache(); + foreach (var key in keyArray) + { + var value = cache.GetOrDefault(key)?.GetUnRemovedValueOrNull(); + if (value != null) + { + cachedValues.Add(new KeyValuePair(key, value)); + } + } + + notCachedKeys = keyArray.Except(cachedValues.Select(x => x.Key)).ToList(); + if (!notCachedKeys.Any()) + { + return cachedValues.ToArray(); + } + } + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; byte[][] cachedBytes; + var readKeys = notCachedKeys.Any() ? notCachedKeys.ToArray() : keyArray; + try { cachedBytes = await cacheSupportsMultipleItems.GetManyAsync( - keyArray.Select(NormalizeKey), + readKeys.Select(NormalizeKey), CancellationTokenProvider.FallbackToProvider(token) ); } @@ -256,17 +326,18 @@ namespace Volo.Abp.Caching if (hideErrors == true) { await HandleExceptionAsync(ex); - return ToCacheItemsWithDefaultValues(keyArray); + return ToCacheItemsWithDefaultValues(readKeys); } throw; } - - return ToCacheItems(cachedBytes, keyArray); + + return cachedValues.Concat(ToCacheItems(cachedBytes, readKeys)).ToArray(); } protected virtual async Task[]> GetManyFallbackAsync( TCacheKey[] keys, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default) { @@ -280,7 +351,7 @@ namespace Volo.Abp.Caching { result.Add(new KeyValuePair( key, - await GetAsync(key, false, token)) + await GetAsync(key, considerUow, hideErrors: false, token: token)) ); } @@ -302,16 +373,27 @@ namespace Volo.Abp.Caching /// Gets a cache item with the given key. If no cache item is found for the given key then returns null. /// /// The key of cached item to be retrieved from the cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The for the task. /// The cache item, or null. public virtual async Task GetAsync( TCacheKey key, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + if (ShouldConsiderUow(considerUow)) + { + var value = GetUnitOfWorkCache().GetOrDefault(key)?.GetUnRemovedValueOrNull(); + if (value != null) + { + return value; + } + } + byte[] cachedBytes; try @@ -347,15 +429,17 @@ namespace Volo.Abp.Caching /// The key of cached item to be retrieved from the cache. /// The factory delegate is used to provide the cache item when no cache item is found for the given . /// The cache options for the factory delegate. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The cache item. public virtual TCacheItem GetOrAdd( TCacheKey key, Func factory, Func optionsFactory = null, + bool considerUow = false, bool? hideErrors = null) { - var value = Get(key, hideErrors); + var value = Get(key, considerUow, hideErrors); if (value != null) { return value; @@ -363,14 +447,28 @@ namespace Volo.Abp.Caching using (SyncSemaphore.Lock()) { - value = Get(key, hideErrors); + value = Get(key, considerUow, hideErrors); if (value != null) { return value; } value = factory(); - Set(key, value, optionsFactory?.Invoke(), hideErrors); + + if (ShouldConsiderUow(considerUow)) + { + var uowCache = GetUnitOfWorkCache(); + if (uowCache.TryGetValue(key, out var item)) + { + item.SetValue(value); + } + else + { + uowCache.Add(key, new UnitOfWorkCacheItem(value)); + } + } + + Set(key, value, optionsFactory?.Invoke(), considerUow, hideErrors); } return value; @@ -384,17 +482,19 @@ namespace Volo.Abp.Caching /// The factory delegate is used to provide the cache item when no cache item is found for the given . /// The cache options for the factory delegate. /// Indicates to throw or hide the exceptions for the distributed cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// The for the task. /// The cache item. public virtual async Task GetOrAddAsync( TCacheKey key, Func> factory, Func optionsFactory = null, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default) { token = CancellationTokenProvider.FallbackToProvider(token); - var value = await GetAsync(key, hideErrors, token); + var value = await GetAsync(key, considerUow, hideErrors, token); if (value != null) { return value; @@ -402,14 +502,28 @@ namespace Volo.Abp.Caching using (await SyncSemaphore.LockAsync(token)) { - value = await GetAsync(key, hideErrors, token); + value = await GetAsync(key, considerUow, hideErrors, token); if (value != null) { return value; } value = await factory(); - await SetAsync(key, value, optionsFactory?.Invoke(), hideErrors, token); + + if (ShouldConsiderUow(considerUow)) + { + var uowCache = GetUnitOfWorkCache(); + if (uowCache.TryGetValue(key, out var item)) + { + item.SetValue(value); + } + else + { + uowCache.Add(key, new UnitOfWorkCacheItem(value)); + } + } + + await SetAsync(key, value, optionsFactory?.Invoke(), considerUow, hideErrors, token); } return value; @@ -421,41 +535,70 @@ namespace Volo.Abp.Caching /// The key of cached item to be retrieved from the cache. /// The cache item value to set in the cache. /// The cache options for the value. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. public virtual void Set( TCacheKey key, TCacheItem value, DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null) { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try + void SetRealCache() { - Cache.Set( - NormalizeKey(key), - Serializer.Serialize(value), - options ?? DefaultCacheOptions - ); + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + Cache.Set( + NormalizeKey(key), + Serializer.Serialize(value), + options ?? DefaultCacheOptions + ); + } + catch (Exception ex) + { + if (hideErrors == true) + { + HandleException(ex); + return; + } + + throw; + } } - catch (Exception ex) + + if (ShouldConsiderUow(considerUow)) { - if (hideErrors == true) + var cache = GetUnitOfWorkCache(); + if (cache.TryGetValue(key, out _)) { - HandleException(ex); - return; + cache[key].SetValue(value); + } + else + { + cache.Add(key, new UnitOfWorkCacheItem(value)); } - throw; + // ReSharper disable once PossibleNullReferenceException + UnitOfWorkManager.Current.OnCompleted(() => + { + SetRealCache(); + return Task.CompletedTask; + }); + } + else + { + SetRealCache(); } } - /// /// Sets the cache item value for the provided key. /// /// The key of cached item to be retrieved from the cache. /// The cache item value to set in the cache. /// The cache options for the value. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The for the task. /// The indicating that the operation is asynchronous. @@ -463,35 +606,60 @@ namespace Volo.Abp.Caching TCacheKey key, TCacheItem value, DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default) { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try + async Task SetRealCache() { - await Cache.SetAsync( - NormalizeKey(key), - Serializer.Serialize(value), - options ?? DefaultCacheOptions, - CancellationTokenProvider.FallbackToProvider(token) - ); - } - catch (Exception ex) - { - if (hideErrors == true) + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try { - await HandleExceptionAsync(ex); - return; + await Cache.SetAsync( + NormalizeKey(key), + Serializer.Serialize(value), + options ?? DefaultCacheOptions, + CancellationTokenProvider.FallbackToProvider(token) + ); } + catch (Exception ex) + { + if (hideErrors == true) + { + await HandleExceptionAsync(ex); + return; + } - throw; + throw; + } } + + if (ShouldConsiderUow(considerUow)) + { + var cache = GetUnitOfWorkCache(); + if (cache.TryGetValue(key, out _)) + { + cache[key].SetValue(value); + } + else + { + cache.Add(key, new UnitOfWorkCacheItem(value)); + } + + // ReSharper disable once PossibleNullReferenceException + UnitOfWorkManager.Current.OnCompleted(SetRealCache); + } + else + { + await SetRealCache(); + } } public void SetMany( IEnumerable> items, DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null) { var itemsArray = items.ToArray(); @@ -502,40 +670,73 @@ namespace Volo.Abp.Caching SetManyFallback( itemsArray, options, + considerUow, hideErrors ); - + return; } - - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - try + void SetRealCache() { - cacheSupportsMultipleItems.SetMany( - ToRawCacheItems(itemsArray), - options ?? DefaultCacheOptions - ); + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + cacheSupportsMultipleItems.SetMany( + ToRawCacheItems(itemsArray), + options ?? DefaultCacheOptions + ); + } + catch (Exception ex) + { + if (hideErrors == true) + { + HandleException(ex); + return; + } + + throw; + } } - catch (Exception ex) + + if (ShouldConsiderUow(considerUow)) { - if (hideErrors == true) + var cache = GetUnitOfWorkCache(); + + foreach (var pair in itemsArray) { - HandleException(ex); - return; + if (cache.TryGetValue(pair.Key, out _)) + { + cache[pair.Key].SetValue(pair.Value); + } + else + { + cache.Add(pair.Key, new UnitOfWorkCacheItem(pair.Value)); + } } - throw; + // ReSharper disable once PossibleNullReferenceException + UnitOfWorkManager.Current.OnCompleted(() => + { + SetRealCache(); + return Task.CompletedTask; + }); + } + else + { + SetRealCache(); } } - + protected virtual void SetManyFallback( KeyValuePair[] items, DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - + try { foreach (var item in items) @@ -543,7 +744,8 @@ namespace Volo.Abp.Caching Set( item.Key, item.Value, - options: options, + options, + considerUow, hideErrors: false ); } @@ -563,6 +765,7 @@ namespace Volo.Abp.Caching public virtual async Task SetManyAsync( IEnumerable> items, DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default) { @@ -574,38 +777,67 @@ namespace Volo.Abp.Caching await SetManyFallbackAsync( itemsArray, options, + considerUow, hideErrors, token ); - + return; } - - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - try + async Task SetRealCache() { - await cacheSupportsMultipleItems.SetManyAsync( - ToRawCacheItems(itemsArray), - options ?? DefaultCacheOptions, - CancellationTokenProvider.FallbackToProvider(token) - ); + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + await cacheSupportsMultipleItems.SetManyAsync( + ToRawCacheItems(itemsArray), + options ?? DefaultCacheOptions, + CancellationTokenProvider.FallbackToProvider(token) + ); + } + catch (Exception ex) + { + if (hideErrors == true) + { + await HandleExceptionAsync(ex); + return; + } + + throw; + } } - catch (Exception ex) + + if (ShouldConsiderUow(considerUow)) { - if (hideErrors == true) + var cache = GetUnitOfWorkCache(); + + foreach (var pair in itemsArray) { - await HandleExceptionAsync(ex); - return; + if (cache.TryGetValue(pair.Key, out _)) + { + cache[pair.Key].SetValue(pair.Value); + } + else + { + cache.Add(pair.Key, new UnitOfWorkCacheItem(pair.Value)); + } } - throw; + // ReSharper disable once PossibleNullReferenceException + UnitOfWorkManager.Current.OnCompleted(SetRealCache); + } + else + { + await SetRealCache(); } } - + protected virtual async Task SetManyFallbackAsync( KeyValuePair[] items, DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default) { @@ -618,7 +850,8 @@ namespace Volo.Abp.Caching await SetAsync( item.Key, item.Value, - options: options, + options, + considerUow, hideErrors: false, token: token ); @@ -636,9 +869,14 @@ namespace Volo.Abp.Caching } } + /// + /// Refreshes the cache value of the given key, and resets its sliding expiration timeout. + /// + /// The key of cached item to be retrieved from the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. public virtual void Refresh( - TCacheKey key, bool? - hideErrors = null) + TCacheKey key, + bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -658,6 +896,13 @@ namespace Volo.Abp.Caching } } + /// + /// Refreshes the cache value of the given key, and resets its sliding expiration timeout. + /// + /// The key of cached item to be retrieved from the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. + /// The for the task. + /// The indicating that the operation is asynchronous. public virtual async Task RefreshAsync( TCacheKey key, bool? hideErrors = null, @@ -681,48 +926,106 @@ namespace Volo.Abp.Caching } } + /// + /// Removes the cache item for given key from cache. + /// + /// The key of cached item to be retrieved from the cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. public virtual void Remove( TCacheKey key, + bool considerUow = false, bool? hideErrors = null) { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try + void RemoveRealCache() { - Cache.Remove(NormalizeKey(key)); + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + Cache.Remove(NormalizeKey(key)); + } + catch (Exception ex) + { + if (hideErrors == true) + { + HandleException(ex); + return; + } + + throw; + } } - catch (Exception ex) + + if (ShouldConsiderUow(considerUow)) { - if (hideErrors == true) + var cache = GetUnitOfWorkCache(); + if (cache.TryGetValue(key, out _)) { - HandleException(ex); - return; + cache[key].RemoveValue(); } - throw; + // ReSharper disable once PossibleNullReferenceException + UnitOfWorkManager.Current.OnCompleted(() => + { + RemoveRealCache(); + return Task.CompletedTask; + }); + } + else + { + RemoveRealCache(); } } + /// + /// Removes the cache item for given key from cache. + /// + /// The key of cached item to be retrieved from the cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. + /// The for the task. + /// The indicating that the operation is asynchronous. public virtual async Task RemoveAsync( TCacheKey key, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default) { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try + async Task RemoveRealCache() { - await Cache.RemoveAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token)); + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + await Cache.RemoveAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token)); + } + catch (Exception ex) + { + if (hideErrors == true) + { + await HandleExceptionAsync(ex); + return; + } + + throw; + } } - catch (Exception ex) + + if (ShouldConsiderUow(considerUow)) { - if (hideErrors == true) + var cache = GetUnitOfWorkCache(); + if (cache.TryGetValue(key, out _)) { - await HandleExceptionAsync(ex); - return; + cache[key].RemoveValue(); } - throw; + // ReSharper disable once PossibleNullReferenceException + UnitOfWorkManager.Current.OnCompleted(RemoveRealCache); + } + else + { + await RemoveRealCache(); } } @@ -730,7 +1033,7 @@ namespace Volo.Abp.Caching { AsyncHelper.RunSync(() => HandleExceptionAsync(ex)); } - + protected virtual async Task HandleExceptionAsync(Exception ex) { Logger.LogException(ex, LogLevel.Warning); @@ -742,7 +1045,7 @@ namespace Volo.Abp.Caching .NotifyAsync(new ExceptionNotificationContext(ex, LogLevel.Warning)); } } - + protected virtual KeyValuePair[] ToCacheItems(byte[][] itemBytes, TCacheKey[] itemKeys) { if (itemBytes.Length != itemKeys.Length) @@ -764,7 +1067,7 @@ namespace Volo.Abp.Caching return result.ToArray(); } - + [CanBeNull] protected virtual TCacheItem ToCacheItem([CanBeNull] byte[] bytes) { @@ -786,12 +1089,33 @@ namespace Volo.Abp.Caching ) ).ToArray(); } - + private static KeyValuePair[] ToCacheItemsWithDefaultValues(TCacheKey[] keys) { return keys .Select(key => new KeyValuePair(key, default)) .ToArray(); } + + protected virtual bool ShouldConsiderUow(bool considerUow) + { + return considerUow && UnitOfWorkManager.Current != null; + } + + protected virtual string GetUnitOfWorkCacheKey() + { + return DistributedCacheName + CacheName; + } + + protected virtual Dictionary> GetUnitOfWorkCache() + { + if (UnitOfWorkManager.Current == null) + { + throw new AbpException($"There is no unit of work in the current context, The {GetType().Name} can only be used in a unit of work."); + } + + return UnitOfWorkManager.Current.GetOrAddItem(GetUnitOfWorkCacheKey(), + key => new Dictionary>()); + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs index 80fe124785..1b0e58815e 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs @@ -29,42 +29,48 @@ namespace Volo.Abp.Caching /// Gets a cache item with the given key. If no cache item is found for the given key then returns null. /// /// The key of cached item to be retrieved from the cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The cache item, or null. TCacheItem Get( TCacheKey key, + bool considerUow = false, bool? hideErrors = null ); - + /// /// Gets multiple cache items with the given keys. /// /// The returned list contains exactly the same count of items specified in the given keys. /// An item in the return list can not be null, but an item in the list has null value - /// if the related key not found in the cache. + /// if the related key not found in the cache. /// /// The keys of cached items to be retrieved from the cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// List of cache items. KeyValuePair[] GetMany( IEnumerable keys, + bool considerUow = false, bool? hideErrors = null ); - + /// /// Gets multiple cache items with the given keys. /// /// The returned list contains exactly the same count of items specified in the given keys. /// An item in the return list can not be null, but an item in the list has null value /// if the related key not found in the cache. - /// + /// /// /// The keys of cached items to be retrieved from the cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// /// The for the task. /// List of cache items. Task[]> GetManyAsync( IEnumerable keys, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default ); @@ -74,10 +80,12 @@ namespace Volo.Abp.Caching /// /// The key of cached item to be retrieved from the cache. /// Indicates to throw or hide the exceptions for the distributed cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// The for the task. /// The cache item, or null. Task GetAsync( [NotNull] TCacheKey key, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default ); @@ -89,12 +97,14 @@ namespace Volo.Abp.Caching /// The key of cached item to be retrieved from the cache. /// The factory delegate is used to provide the cache item when no cache item is found for the given . /// The cache options for the factory delegate. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The cache item. TCacheItem GetOrAdd( TCacheKey key, Func factory, Func optionsFactory = null, + bool considerUow = false, bool? hideErrors = null ); @@ -105,6 +115,7 @@ namespace Volo.Abp.Caching /// The key of cached item to be retrieved from the cache. /// The factory delegate is used to provide the cache item when no cache item is found for the given . /// The cache options for the factory delegate. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The for the task. /// The cache item. @@ -112,6 +123,7 @@ namespace Volo.Abp.Caching [NotNull] TCacheKey key, Func> factory, Func optionsFactory = null, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default ); @@ -122,11 +134,13 @@ namespace Volo.Abp.Caching /// The key of cached item to be retrieved from the cache. /// The cache item value to set in the cache. /// The cache options for the value. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. void Set( TCacheKey key, TCacheItem value, DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null ); @@ -136,6 +150,7 @@ namespace Volo.Abp.Caching /// The key of cached item to be retrieved from the cache. /// The cache item value to set in the cache. /// The cache options for the value. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The for the task. /// The indicating that the operation is asynchronous. @@ -143,6 +158,7 @@ namespace Volo.Abp.Caching [NotNull] TCacheKey key, [NotNull] TCacheItem value, [CanBeNull] DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default ); @@ -153,25 +169,29 @@ namespace Volo.Abp.Caching /// /// Items to set on the cache /// The cache options for the value. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. void SetMany( IEnumerable> items, DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null ); - + /// /// Sets multiple cache items. /// Based on the implementation, this can be more efficient than setting multiple items individually. /// /// Items to set on the cache /// The cache options for the value. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The for the task. /// The indicating that the operation is asynchronous. Task SetManyAsync( IEnumerable> items, DistributedCacheEntryOptions options = null, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default ); @@ -203,9 +223,11 @@ namespace Volo.Abp.Caching /// Removes the cache item for given key from cache. /// /// The key of cached item to be retrieved from the cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. void Remove( TCacheKey key, + bool considerUow = false, bool? hideErrors = null ); @@ -213,11 +235,13 @@ namespace Volo.Abp.Caching /// Removes the cache item for given key from cache. /// /// The key of cached item to be retrieved from the cache. + /// This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache. /// Indicates to throw or hide the exceptions for the distributed cache. /// The for the task. /// The indicating that the operation is asynchronous. Task RemoveAsync( TCacheKey key, + bool considerUow = false, bool? hideErrors = null, CancellationToken token = default ); diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/UnitOfWorkCacheItem.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/UnitOfWorkCacheItem.cs new file mode 100644 index 0000000000..c37475d022 --- /dev/null +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/UnitOfWorkCacheItem.cs @@ -0,0 +1,43 @@ +using System; + +namespace Volo.Abp.Caching +{ + [Serializable] + public class UnitOfWorkCacheItem + where TValue : class + { + public bool IsRemoved { get; set; } + + public TValue Value { get; set; } + + public UnitOfWorkCacheItem() + { + + } + + public UnitOfWorkCacheItem(TValue value) + { + Value = value; + } + + public UnitOfWorkCacheItem(TValue value, bool isRemoved) + { + Value = value; + IsRemoved = isRemoved; + } + + public UnitOfWorkCacheItem SetValue(TValue value) + { + Value = value; + IsRemoved = false; + return this; + } + + public UnitOfWorkCacheItem RemoveValue() + { + Value = null; + IsRemoved = true; + return this; + } + } +} diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/UnitOfWorkCacheItemExtensions.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/UnitOfWorkCacheItemExtensions.cs new file mode 100644 index 0000000000..46757f80cf --- /dev/null +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/UnitOfWorkCacheItemExtensions.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.Caching +{ + public static class UnitOfWorkCacheItemExtensions + { + public static TValue GetUnRemovedValueOrNull(this UnitOfWorkCacheItem item) + where TValue : class + { + return item != null && !item.IsRemoved ? item.Value : null; + } + } +} diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index b42b745fb4..b4158229fe 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; @@ -316,4 +316,4 @@ namespace Volo.Abp.Uow return $"[UnitOfWork {Id}]"; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkExtensions.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkExtensions.cs index 5c01f54a99..c183a70390 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkExtensions.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkExtensions.cs @@ -1,4 +1,7 @@ -using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; namespace Volo.Abp.Uow { @@ -10,5 +13,43 @@ namespace Volo.Abp.Uow return unitOfWork.IsReserved && unitOfWork.ReservationName == reservationName; } + + public static void AddItem([NotNull] this IUnitOfWork unitOfWork, string key, TValue value) + where TValue : class + { + Check.NotNull(unitOfWork, nameof(unitOfWork)); + + if (!unitOfWork.Items.ContainsKey(key)) + { + unitOfWork.Items[key] = value; + } + else + { + unitOfWork.Items.Add(key, value); + } + } + + public static TValue GetItemOrDefault([NotNull] this IUnitOfWork unitOfWork, string key) + where TValue : class + { + Check.NotNull(unitOfWork, nameof(unitOfWork)); + + return unitOfWork.Items.FirstOrDefault(x => x.Key == key).As(); + } + + public static TValue GetOrAddItem([NotNull] this IUnitOfWork unitOfWork, string key, Func factory) + where TValue : class + { + Check.NotNull(unitOfWork, nameof(unitOfWork)); + + return unitOfWork.Items.GetOrAdd(key, factory).As(); + } + + public static void RemoveItem([NotNull] this IUnitOfWork unitOfWork, string key) + { + Check.NotNull(unitOfWork, nameof(unitOfWork)); + + unitOfWork.Items.RemoveAll(x => x.Key == key); + } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs index 533362c851..61a61ac2cd 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Shouldly; using Volo.Abp.Testing; +using Volo.Abp.Uow; using Xunit; namespace Volo.Abp.Caching @@ -30,7 +31,7 @@ namespace Volo.Abp.Caching cacheItem.ShouldNotBeNull(); cacheItem.Name.ShouldBe(personName); - //Remove + //Remove await personCache.RemoveAsync(cacheKey); //Get (not exists since removed) @@ -111,7 +112,7 @@ namespace Volo.Abp.Caching cacheItem1.ShouldNotBeNull(); cacheItem1.Name.ShouldBe(personName); - //Remove + //Remove await personCache.RemoveAsync(cacheKey); @@ -145,7 +146,7 @@ namespace Volo.Abp.Caching cacheItem.ShouldNotBeNull(); cacheItem.Name.ShouldBe(personName); - //Remove + //Remove await personCache.RemoveAsync(cacheKey); //Get (not exists since removed) @@ -227,7 +228,7 @@ namespace Volo.Abp.Caching cacheItem1.ShouldNotBeNull(); cacheItem1.Name.ShouldBe(personName); - //Remove + //Remove await personCache.RemoveAsync(cacheKey); @@ -261,7 +262,7 @@ namespace Volo.Abp.Caching cacheItem.ShouldNotBeNull(); cacheItem.Name.ShouldBe(personName); - //Remove + //Remove await personCache.RemoveAsync(cacheKey); //Get (not exists since removed) @@ -299,7 +300,7 @@ namespace Volo.Abp.Caching cacheItem2.ShouldNotBeNull(); cacheItem2.Name.ShouldBe(personName); - //Remove + //Remove await personCache.RemoveAsync(cache1Key); await personCache.RemoveAsync(cache2Key); @@ -310,6 +311,235 @@ namespace Volo.Abp.Caching cacheItem2.ShouldBeNull(); } + [Fact] + public async Task Cache_Should_Only_Available_In_Uow_For_GetAsync() + { + const string key = "testkey"; + + using (var uow = GetRequiredService().Begin()) + { + var personCache = GetRequiredService>(); + + var cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldBeNull(); + + await personCache.SetAsync(key, new PersonCacheItem("john"), considerUow: true); + + cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + + uow.OnCompleted(async () => + { + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + }); + + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task Cache_Should_Rollback_With_Uow_For_GetAsync() + { + const string key = "testkey"; + var personCache = GetRequiredService>(); + + var cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + + using (var uow = GetRequiredService().Begin()) + { + cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldBeNull(); + + await personCache.SetAsync(key, new PersonCacheItem("john"), considerUow: true); + + cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + } + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + } + + [Fact] + public async Task Cache_Should_Only_Available_In_Uow_For_GetOrAddAsync() + { + const string key = "testkey"; + + using (var uow = GetRequiredService().Begin()) + { + var personCache = GetRequiredService>(); + + var cacheValue = await personCache.GetOrAddAsync(key, () => Task.FromResult(new PersonCacheItem("john")), considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + + uow.OnCompleted(async () => + { + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + }); + + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task Cache_Should_Rollback_With_Uow_For_GetOrAddAsync() + { + const string key = "testkey"; + var personCache = GetRequiredService>(); + + var cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + + using (var uow = GetRequiredService().Begin()) + { + cacheValue = await personCache.GetOrAddAsync(key, () => Task.FromResult(new PersonCacheItem("john")), considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + } + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + } + + [Fact] + public async Task Cache_Should_Only_Available_In_Uow_For_SetAsync() + { + const string key = "testkey"; + + using (var uow = GetRequiredService().Begin()) + { + var personCache = GetRequiredService>(); + + await personCache.SetAsync(key, new PersonCacheItem("john"), considerUow: true); + + var cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + + uow.OnCompleted(async () => + { + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + }); + + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task Cache_Should_Rollback_With_Uow_For_SetAsync() + { + const string key = "testkey"; + var personCache = GetRequiredService>(); + + var cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + + using (var uow = GetRequiredService().Begin()) + { + await personCache.SetAsync(key, new PersonCacheItem("john"), considerUow: true); + + cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + } + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + } + + [Fact] + public async Task Cache_Should_Only_Available_In_Uow_For_RemoveAsync() + { + const string key = "testkey"; + + using (var uow = GetRequiredService().Begin()) + { + var personCache = GetRequiredService>(); + + await personCache.SetAsync(key, new PersonCacheItem("john"), considerUow: true); + + var cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + await personCache.RemoveAsync(key, considerUow: true); + + cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldBeNull(); + + uow.OnCompleted(async () => + { + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + }); + + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task Cache_Should_Rollback_With_Uow_For_RemoveAsync() + { + const string key = "testkey"; + var personCache = GetRequiredService>(); + + var cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + + using (var uow = GetRequiredService().Begin()) + { + await personCache.SetAsync(key, new PersonCacheItem("john"), considerUow: true); + + cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldNotBeNull(); + cacheValue.Name.ShouldBe("john"); + + await personCache.RemoveAsync(key, considerUow: true); + + cacheValue = await personCache.GetAsync(key, considerUow: true); + cacheValue.ShouldBeNull(); + } + + cacheValue = await personCache.GetAsync(key, considerUow: false); + cacheValue.ShouldBeNull(); + } + [Fact] public async Task Should_Set_And_Get_Multiple_Items_Async() { @@ -340,4 +570,4 @@ namespace Volo.Abp.Caching (await personCache.GetAsync("baris")).ShouldBeNull(); } } -} \ No newline at end of file +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs index 26388fdaf9..5b892a91bb 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs @@ -5,6 +5,7 @@ using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; using Volo.Abp.Guids; +using Volo.Abp.Uow; namespace Volo.Abp.FeatureManagement { @@ -27,12 +28,14 @@ namespace Volo.Abp.FeatureManagement FeatureDefinitionManager = featureDefinitionManager; } + [UnitOfWork] public virtual async Task GetOrNullAsync(string name, string providerName, string providerKey) { var cacheItem = await GetCacheItemAsync(name, providerName, providerKey); return cacheItem.Value; } + [UnitOfWork] public virtual async Task SetAsync(string name, string value, string providerName, string providerKey) { var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey); @@ -46,21 +49,25 @@ namespace Volo.Abp.FeatureManagement featureValue.Value = value; await FeatureValueRepository.UpdateAsync(featureValue); } + + await Cache.SetAsync(CalculateCacheKey(name, providerName, providerKey), new FeatureValueCacheItem(featureValue?.Value), considerUow: true); } + [UnitOfWork] public virtual async Task DeleteAsync(string name, string providerName, string providerKey) { var featureValues = await FeatureValueRepository.FindAllAsync(name, providerName, providerKey); foreach (var featureValue in featureValues) { await FeatureValueRepository.DeleteAsync(featureValue); + await Cache.RemoveAsync(CalculateCacheKey(name, providerName, providerKey), considerUow: true); } } protected virtual async Task GetCacheItemAsync(string name, string providerName, string providerKey) { var cacheKey = CalculateCacheKey(name, providerName, providerKey); - var cacheItem = await Cache.GetAsync(cacheKey); + var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true); if (cacheItem != null) { @@ -68,28 +75,28 @@ namespace Volo.Abp.FeatureManagement } cacheItem = new FeatureValueCacheItem(null); - + await SetCacheItemsAsync(providerName, providerKey, name, cacheItem); return cacheItem; } - + private async Task SetCacheItemsAsync( - string providerName, - string providerKey, - string currentName, + string providerName, + string providerKey, + string currentName, FeatureValueCacheItem currentCacheItem) { var featureDefinitions = FeatureDefinitionManager.GetAll(); var featuresDictionary = (await FeatureValueRepository.GetListAsync(providerName, providerKey)) .ToDictionary(s => s.Name, s => s.Value); - - var cacheItems = new List>(); - + + var cacheItems = new List>(); + foreach (var featureDefinition in featureDefinitions) { var featureValue = featuresDictionary.GetOrDefault(featureDefinition.Name); - + cacheItems.Add( new KeyValuePair( CalculateCacheKey(featureDefinition.Name, providerName, providerKey), @@ -103,7 +110,7 @@ namespace Volo.Abp.FeatureManagement } } - await Cache.SetManyAsync(cacheItems); + await Cache.SetManyAsync(cacheItems, considerUow: true); } protected virtual string CalculateCacheKey(string name, string providerName, string providerKey) diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs index a6f040dde3..a5250f1804 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Shouldly; using Volo.Abp.Features; using Volo.Abp.Modularity; +using Volo.Abp.Uow; using Xunit; namespace Volo.Abp.FeatureManagement @@ -14,11 +15,13 @@ namespace Volo.Abp.FeatureManagement { private IFeatureManagementStore FeatureManagementStore { get; set; } private IFeatureValueRepository FeatureValueRepository { get; set; } + private IUnitOfWorkManager UnitOfWorkManager { get; set; } protected FeatureManagementStore_Tests() { FeatureManagementStore = GetRequiredService(); FeatureValueRepository = GetRequiredService(); + UnitOfWorkManager = GetRequiredService(); } [Fact] @@ -73,6 +76,30 @@ namespace Volo.Abp.FeatureManagement TestEditionIds.Regular.ToString())).Value.ShouldBe(false.ToString().ToUpperInvariant()); } + [Fact] + public async Task Set_In_UnitOfWork_Should_Be_Consistent() + { + using (UnitOfWorkManager.Begin()) + { + // Arrange + (await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins, + EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString())).ShouldNotBeNull(); + + + // Act + await FeatureManagementStore.SetAsync(TestFeatureDefinitionProvider.SocialLogins, + false.ToString().ToUpperInvariant(), + EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString()); + + // Assert + (await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins, + EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString())).ShouldBe(false.ToString().ToUpperInvariant()); + } + } + [Fact] public async Task DeleteAsync() { @@ -94,5 +121,29 @@ namespace Volo.Abp.FeatureManagement } + + [Fact] + public async Task Delete_In_UnitOfWork_Should_Be_Consistent() + { + using (var uow = UnitOfWorkManager.Begin()) + { + // Arrange + (await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins, + EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString())).ShouldNotBeNull(); + + // Act + await FeatureManagementStore.DeleteAsync(TestFeatureDefinitionProvider.SocialLogins, + EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString()); + + await uow.SaveChangesAsync(); + + // Assert + (await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins, + EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString())).ShouldBeNull(); + } + } } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs index 617d360898..a568184f0e 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs @@ -5,6 +5,7 @@ using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; using Volo.Abp.Settings; +using Volo.Abp.Uow; namespace Volo.Abp.SettingManagement { @@ -16,8 +17,8 @@ namespace Volo.Abp.SettingManagement protected IGuidGenerator GuidGenerator { get; } public SettingManagementStore( - ISettingRepository settingRepository, - IGuidGenerator guidGenerator, + ISettingRepository settingRepository, + IGuidGenerator guidGenerator, IDistributedCache cache, ISettingDefinitionManager settingDefinitionManager) { @@ -27,11 +28,13 @@ namespace Volo.Abp.SettingManagement SettingDefinitionManager = settingDefinitionManager; } + [UnitOfWork] public virtual async Task GetOrNullAsync(string name, string providerName, string providerKey) { return (await GetCacheItemAsync(name, providerName, providerKey)).Value; } + [UnitOfWork] public virtual async Task SetAsync(string name, string value, string providerName, string providerKey) { var setting = await SettingRepository.FindAsync(name, providerName, providerKey); @@ -45,6 +48,8 @@ namespace Volo.Abp.SettingManagement setting.Value = value; await SettingRepository.UpdateAsync(setting); } + + await Cache.SetAsync(CalculateCacheKey(name, providerName, providerKey), new SettingCacheItem(setting?.Value), considerUow: true); } public virtual async Task> GetListAsync(string providerName, string providerKey) @@ -53,19 +58,21 @@ namespace Volo.Abp.SettingManagement return settings.Select(s => new SettingValue(s.Name, s.Value)).ToList(); } + [UnitOfWork] public virtual async Task DeleteAsync(string name, string providerName, string providerKey) { var setting = await SettingRepository.FindAsync(name, providerName, providerKey); if (setting != null) { await SettingRepository.DeleteAsync(setting); + await Cache.RemoveAsync(CalculateCacheKey(name, providerName, providerKey), considerUow: true); } } protected virtual async Task GetCacheItemAsync(string name, string providerName, string providerKey) { var cacheKey = CalculateCacheKey(name, providerName, providerKey); - var cacheItem = await Cache.GetAsync(cacheKey); + var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true); if (cacheItem != null) { @@ -75,26 +82,26 @@ namespace Volo.Abp.SettingManagement cacheItem = new SettingCacheItem(null); await SetCacheItemsAsync(providerName, providerKey, name, cacheItem); - + return cacheItem; } private async Task SetCacheItemsAsync( - string providerName, - string providerKey, - string currentName, + string providerName, + string providerKey, + string currentName, SettingCacheItem currentCacheItem) { var settingDefinitions = SettingDefinitionManager.GetAll(); var settingsDictionary = (await SettingRepository.GetListAsync(providerName, providerKey)) .ToDictionary(s => s.Name, s => s.Value); - - var cacheItems = new List>(); - + + var cacheItems = new List>(); + foreach (var settingDefinition in settingDefinitions) { var settingValue = settingsDictionary.GetOrDefault(settingDefinition.Name); - + cacheItems.Add( new KeyValuePair( CalculateCacheKey(settingDefinition.Name, providerName, providerKey), @@ -108,7 +115,7 @@ namespace Volo.Abp.SettingManagement } } - await Cache.SetManyAsync(cacheItems); + await Cache.SetManyAsync(cacheItems, considerUow: true); } protected virtual string CalculateCacheKey(string name, string providerName, string providerKey) diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs index 753ba15054..7a405faf2d 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading.Tasks; using Shouldly; using Volo.Abp.Settings; +using Volo.Abp.Uow; using Xunit; namespace Volo.Abp.SettingManagement @@ -13,12 +14,14 @@ namespace Volo.Abp.SettingManagement private readonly ISettingManagementStore _settingManagementStore; private readonly ISettingRepository _settingRepository; private readonly SettingTestData _testData; + private readonly IUnitOfWorkManager _unitOfWorkManager; public SettingManagementStore_Tests() { _settingManagementStore = GetRequiredService(); _settingRepository = GetRequiredService(); _testData = GetRequiredService(); + _unitOfWorkManager= GetRequiredService(); } [Fact] @@ -50,6 +53,21 @@ namespace Volo.Abp.SettingManagement (await _settingRepository.FindAsync(_testData.SettingId)).Value.ShouldBe("43"); } + [Fact] + public async Task Set_In_UnitOfWork_Should_Be_Consistent() + { + using (_unitOfWorkManager.Begin()) + { + var value = await _settingManagementStore.GetOrNullAsync("MySetting1", GlobalSettingValueProvider.ProviderName, null); + value.ShouldBe("42"); + + await _settingManagementStore.SetAsync("MySetting1", "43", GlobalSettingValueProvider.ProviderName, null); + + var valueAfterSet = await _settingManagementStore.GetOrNullAsync("MySetting1", GlobalSettingValueProvider.ProviderName, null); + valueAfterSet.ShouldBe("43"); + } + } + [Fact] public async Task DeleteAsync() { @@ -60,5 +78,21 @@ namespace Volo.Abp.SettingManagement (await _settingRepository.FindAsync(_testData.SettingId)).ShouldBeNull(); } + [Fact] + public async Task Delete_In_UnitOfWork_Should_Be_Consistent() + { + using (var uow = _unitOfWorkManager.Begin()) + { + (await _settingManagementStore.GetOrNullAsync("MySetting1", GlobalSettingValueProvider.ProviderName, null)).ShouldNotBeNull(); + + await _settingManagementStore.DeleteAsync("MySetting1", GlobalSettingValueProvider.ProviderName, null); + + await uow.SaveChangesAsync(); + + var value = await _settingManagementStore.GetOrNullAsync("MySetting1", GlobalSettingValueProvider.ProviderName, null); + value.ShouldBeNull(); + } + } + } } From 6f1514da88931591a149a3b4b222f8f0ca7e6ab0 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Wed, 1 Jul 2020 11:53:04 +0800 Subject: [PATCH 003/376] Switch to the tenant before calling the handleevent method. Resolve #4508 --- .../RabbitMq/RabbitMqDistributedEventBus.cs | 14 ++-- .../Volo.Abp.EventBus.csproj | 1 + .../Volo/Abp/EventBus/AbpEventBusModule.cs | 2 + .../Volo/Abp/EventBus/EventBusBase.cs | 80 +++++++++++++------ .../Volo/Abp/EventBus/Local/LocalEventBus.cs | 8 +- .../LocalDistributedEventBus_Test.cs | 29 ++++++- ...leDistributedSingleInstanceEventHandler.cs | 32 ++++++++ .../Local/EventBus_MultiTenancy_Test.cs | 64 +++++++++++++++ .../Volo/Abp/EventBus/MySimpleEventData.cs | 12 ++- 9 files changed, 203 insertions(+), 39 deletions(-) create mode 100644 framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/MySimpleDistributedSingleInstanceEventHandler.cs create mode 100644 framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultiTenancy_Test.cs diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index ed7d37db20..e8c7fc6c5b 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -9,6 +9,7 @@ using RabbitMQ.Client; using RabbitMQ.Client.Events; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; +using Volo.Abp.MultiTenancy; using Volo.Abp.RabbitMQ; using Volo.Abp.Threading; @@ -26,7 +27,7 @@ namespace Volo.Abp.EventBus.RabbitMq protected AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; } protected IConnectionPool ConnectionPool { get; } protected IRabbitMqSerializer Serializer { get; } - + //TODO: Accessing to the List may not be thread-safe! protected ConcurrentDictionary> HandlerFactories { get; } protected ConcurrentDictionary EventTypes { get; } @@ -37,17 +38,18 @@ namespace Volo.Abp.EventBus.RabbitMq IOptions options, IConnectionPool connectionPool, IRabbitMqSerializer serializer, - IServiceScopeFactory serviceScopeFactory, + IServiceScopeFactory serviceScopeFactory, IOptions distributedEventBusOptions, - IRabbitMqMessageConsumerFactory messageConsumerFactory) - : base(serviceScopeFactory) + IRabbitMqMessageConsumerFactory messageConsumerFactory, + ICurrentTenant currentTenant) + : base(serviceScopeFactory, currentTenant) { ConnectionPool = connectionPool; Serializer = serializer; MessageConsumerFactory = messageConsumerFactory; AbpDistributedEventBusOptions = distributedEventBusOptions.Value; AbpRabbitMqEventBusOptions = options.Value; - + HandlerFactories = new ConcurrentDictionary>(); EventTypes = new ConcurrentDictionary(); } @@ -178,7 +180,7 @@ namespace Volo.Abp.EventBus.RabbitMq "direct", durable: true ); - + var properties = channel.CreateBasicProperties(); properties.DeliveryMode = RabbitMqConsts.DeliveryModes.Persistent; diff --git a/framework/src/Volo.Abp.EventBus/Volo.Abp.EventBus.csproj b/framework/src/Volo.Abp.EventBus/Volo.Abp.EventBus.csproj index 566767e111..a1799c6673 100644 --- a/framework/src/Volo.Abp.EventBus/Volo.Abp.EventBus.csproj +++ b/framework/src/Volo.Abp.EventBus/Volo.Abp.EventBus.csproj @@ -16,6 +16,7 @@ + diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs index c5a5022f77..81c3393a50 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs @@ -4,10 +4,12 @@ using System.Collections.Generic; using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Local; using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; using Volo.Abp.Reflection; namespace Volo.Abp.EventBus { + [DependsOn(typeof(AbpMultiTenancyModule))] public class AbpEventBusModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs index a7883950d1..6c3f93814a 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Collections; using Volo.Abp.EventBus.Distributed; +using Volo.Abp.MultiTenancy; using Volo.Abp.Reflection; namespace Volo.Abp.EventBus @@ -16,9 +17,12 @@ namespace Volo.Abp.EventBus { protected IServiceScopeFactory ServiceScopeFactory { get; } - protected EventBusBase(IServiceScopeFactory serviceScopeFactory) + protected ICurrentTenant CurrentTenant { get; } + + protected EventBusBase(IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant) { ServiceScopeFactory = serviceScopeFactory; + CurrentTenant = currentTenant; } /// @@ -162,31 +166,34 @@ namespace Volo.Abp.EventBus { var handlerType = eventHandlerWrapper.EventHandler.GetType(); - if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(ILocalEventHandler<>))) - { - var method = typeof(ILocalEventHandler<>) - .MakeGenericType(eventType) - .GetMethod( - nameof(ILocalEventHandler.HandleEventAsync), - new[] { eventType } - ); - - await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData })); - } - else if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(IDistributedEventHandler<>))) - { - var method = typeof(IDistributedEventHandler<>) - .MakeGenericType(eventType) - .GetMethod( - nameof(IDistributedEventHandler.HandleEventAsync), - new[] { eventType } - ); - - await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData })); - } - else + using (CurrentTenant.Change(GetEventDataTenantId(eventData))) { - throw new AbpException("The object instance is not an event handler. Object type: " + handlerType.AssemblyQualifiedName); + if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(ILocalEventHandler<>))) + { + var method = typeof(ILocalEventHandler<>) + .MakeGenericType(eventType) + .GetMethod( + nameof(ILocalEventHandler.HandleEventAsync), + new[] { eventType } + ); + + await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData })); + } + else if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(IDistributedEventHandler<>))) + { + var method = typeof(IDistributedEventHandler<>) + .MakeGenericType(eventType) + .GetMethod( + nameof(IDistributedEventHandler.HandleEventAsync), + new[] { eventType } + ); + + await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData })); + } + else + { + throw new AbpException("The object instance is not an event handler. Object type: " + handlerType.AssemblyQualifiedName); + } } } catch (TargetInvocationException ex) @@ -200,6 +207,27 @@ namespace Volo.Abp.EventBus } } + protected virtual Guid? GetEventDataTenantId(object eventData) + { + if (eventData is IMultiTenant multiTenantEventData) + { + return multiTenantEventData.TenantId; + } + + //TODO: Cache propertyInfo & Use interface or class to get Entity property. + var propertyInfo = eventData.GetType().GetProperty("Entity"); + if (propertyInfo != null && propertyInfo.GetGetMethod(true) != null) + { + var entity = propertyInfo.GetValue(eventData); + if (entity != null && entity is IMultiTenant multiTenantEntity) + { + return multiTenantEntity.TenantId; + } + } + + return CurrentTenant.Id; + } + protected class EventTypeWithEventHandlerFactories { public Type EventType { get; } @@ -246,4 +274,4 @@ namespace Volo.Abp.EventBus } } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs index 7db5c18f01..8c7bef6f2d 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; namespace Volo.Abp.EventBus.Local @@ -29,8 +30,9 @@ namespace Volo.Abp.EventBus.Local public LocalEventBus( IOptions options, - IServiceScopeFactory serviceScopeFactory) - : base(serviceScopeFactory) + IServiceScopeFactory serviceScopeFactory, + ICurrentTenant currentTenant) + : base(serviceScopeFactory, currentTenant) { Options = options.Value; Logger = NullLogger.Instance; @@ -166,4 +168,4 @@ namespace Volo.Abp.EventBus.Local return false; } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs index 47649ad3c3..d3371f383a 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs @@ -1,4 +1,7 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.MultiTenancy; using Xunit; namespace Volo.Abp.EventBus.Distributed @@ -17,5 +20,29 @@ namespace Volo.Abp.EventBus.Distributed Assert.Equal(3, MySimpleDistributedTransientEventHandler.HandleCount); Assert.Equal(3, MySimpleDistributedTransientEventHandler.DisposeCount); } + + [Fact] + public async Task Should_Change_TenantId_If_EventData_Is_MultiTenant() + { + var tenantId = Guid.NewGuid(); + + DistributedEventBus.Subscribe(GetRequiredService()); + + await DistributedEventBus.PublishAsync(new MySimpleEventData(3, tenantId)); + + Assert.Equal(tenantId, MySimpleDistributedSingleInstanceEventHandler.TenantId); + } + + [Fact] + public async Task Should_Change_TenantId_If_Generic_EventData_Is_MultiTenant() + { + var tenantId = Guid.NewGuid(); + + DistributedEventBus.Subscribe>(GetRequiredService()); + + await DistributedEventBus.PublishAsync(new MySimpleEventData(3, tenantId)); + + Assert.Equal(tenantId, MySimpleDistributedSingleInstanceEventHandler.TenantId); + } } } diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/MySimpleDistributedSingleInstanceEventHandler.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/MySimpleDistributedSingleInstanceEventHandler.cs new file mode 100644 index 0000000000..53fe8e347b --- /dev/null +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/MySimpleDistributedSingleInstanceEventHandler.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.EventBus.Distributed +{ + public class MySimpleDistributedSingleInstanceEventHandler : IDistributedEventHandler, IDistributedEventHandler>, ITransientDependency + { + private readonly ICurrentTenant _currentTenant; + + public MySimpleDistributedSingleInstanceEventHandler(ICurrentTenant currentTenant) + { + _currentTenant = currentTenant; + } + + public static Guid? TenantId { get; set; } + + public Task HandleEventAsync(MySimpleEventData eventData) + { + TenantId = _currentTenant.Id; + return Task.CompletedTask; + } + + public Task HandleEventAsync(EntityCreatedEto eventData) + { + TenantId = _currentTenant.Id; + return Task.CompletedTask; + } + } +} diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultiTenancy_Test.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultiTenancy_Test.cs new file mode 100644 index 0000000000..62dcb33b42 --- /dev/null +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultiTenancy_Test.cs @@ -0,0 +1,64 @@ +using System; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.MultiTenancy; +using Xunit; + +namespace Volo.Abp.EventBus.Local +{ + public class EventBus_MultiTenancy_Test : EventBusTestBase + { + [Fact] + public async Task Should_Change_TenantId_If_EventData_Is_MultiTenant() + { + var tenantId = Guid.NewGuid(); + var handler = new MyEventHandler(GetRequiredService()); + + LocalEventBus.Subscribe>(handler); + + await LocalEventBus.PublishAsync(new EntityCreatedEventData(new MyEntity(tenantId))); + + handler.TenantId.ShouldBe(tenantId); + } + + public class MyEntity : Entity, IMultiTenant + { + public override object[] GetKeys() + { + return new object[0]; + } + + public MyEntity() + { + + } + + public MyEntity(Guid? tenantId) + { + TenantId = tenantId; + } + + public Guid? TenantId { get; } + } + + public class MyEventHandler : ILocalEventHandler> + { + private readonly ICurrentTenant _currentTenant; + + public MyEventHandler(ICurrentTenant currentTenant) + { + _currentTenant = currentTenant; + } + + public Guid? TenantId { get; set; } + + public Task HandleEventAsync(EntityChangedEventData eventData) + { + TenantId = _currentTenant.Id; + return Task.CompletedTask; + } + } + } +} diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleEventData.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleEventData.cs index 08142b3355..45a3e7f237 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleEventData.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleEventData.cs @@ -1,12 +1,18 @@ +using System; +using Volo.Abp.MultiTenancy; + namespace Volo.Abp.EventBus { - public class MySimpleEventData + public class MySimpleEventData : IMultiTenant { public int Value { get; set; } - public MySimpleEventData(int value) + public Guid? TenantId { get; } + + public MySimpleEventData(int value, Guid? tenantId = null) { Value = value; + TenantId = tenantId; } } -} \ No newline at end of file +} From a874455eda5bf70326ab02654f4971e50f094ae3 Mon Sep 17 00:00:00 2001 From: wakuflair Date: Thu, 2 Jul 2020 18:19:06 +0800 Subject: [PATCH 004/376] TagHelper: Suppress label generation if "nolabel" specified --- .../TagHelpers/Form/AbpInputTagHelperService.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index 4ddf44d2d6..b5c4b7ec37 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -247,7 +247,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual async Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) { - if (IsOutputHidden(inputTag)) + if (IsOutputHidden(inputTag) || SuppressLabel(inputTag)) { return ""; } @@ -433,6 +433,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form return idAttr != null ? "for=\"" + idAttr.Value + "\"" : ""; } + protected virtual bool SuppressLabel(TagHelperOutput inputTag) + { + return inputTag.AllAttributes.ContainsName("nolabel"); + } + protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool suppress) { var list = context.GetValue>(FormGroupContents) ?? new List(); From 667e52c142861cb1b5b2b479d80a98470a4282be Mon Sep 17 00:00:00 2001 From: wakuflair Date: Thu, 2 Jul 2020 18:27:47 +0800 Subject: [PATCH 005/376] Fix wrong property usage --- .../TagHelpers/Form/AbpInputTagHelperService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index b5c4b7ec37..f6abd15d6b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -435,7 +435,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual bool SuppressLabel(TagHelperOutput inputTag) { - return inputTag.AllAttributes.ContainsName("nolabel"); + return inputTag.Attributes.ContainsName("nolabel"); } protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool suppress) From f219d9bf9346d8650c2d5b38b3c72a18ba59e148 Mon Sep 17 00:00:00 2001 From: wakuflair Date: Thu, 2 Jul 2020 18:33:33 +0800 Subject: [PATCH 006/376] Rename `SuppressLabel` to `ShouldSuppressLabel` --- .../TagHelpers/Form/AbpInputTagHelperService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index f6abd15d6b..55aeafc4ea 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -247,7 +247,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual async Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) { - if (IsOutputHidden(inputTag) || SuppressLabel(inputTag)) + if (IsOutputHidden(inputTag) || ShouldSuppressLabel(inputTag)) { return ""; } @@ -433,7 +433,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form return idAttr != null ? "for=\"" + idAttr.Value + "\"" : ""; } - protected virtual bool SuppressLabel(TagHelperOutput inputTag) + protected virtual bool ShouldSuppressLabel(TagHelperOutput inputTag) { return inputTag.Attributes.ContainsName("nolabel"); } 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 007/376] 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 300bbb39badbd18a6818b1af172a3cbea0c6f4be Mon Sep 17 00:00:00 2001 From: wakuflair Date: Mon, 6 Jul 2020 10:34:37 +0800 Subject: [PATCH 008/376] Introduced `SuppressLabel` property instead of `nolabel` attribute --- .../TagHelpers/Form/AbpInputTagHelper.cs | 2 ++ .../TagHelpers/Form/AbpInputTagHelperService.cs | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs index efd3af2d2c..711e8dfb6c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs @@ -36,6 +36,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form public string Value { get; set; } + public bool SuppressLabel { get; set; } + public AbpInputTagHelper(AbpInputTagHelperService tagHelperService) : base(tagHelperService) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index 55aeafc4ea..58a88c676f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -247,7 +247,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual async Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) { - if (IsOutputHidden(inputTag) || ShouldSuppressLabel(inputTag)) + if (IsOutputHidden(inputTag) || TagHelper.SuppressLabel) { return ""; } @@ -433,11 +433,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form return idAttr != null ? "for=\"" + idAttr.Value + "\"" : ""; } - protected virtual bool ShouldSuppressLabel(TagHelperOutput inputTag) - { - return inputTag.Attributes.ContainsName("nolabel"); - } - protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool suppress) { var list = context.GetValue>(FormGroupContents) ?? new List(); From e7e1f3fe73c51f382a67fca72f27e2f2a2ba76de Mon Sep 17 00:00:00 2001 From: wakuflair Date: Mon, 6 Jul 2020 10:35:02 +0800 Subject: [PATCH 009/376] Added "Suppress Label Generation" demo --- .../Pages/Components/FormElements.cshtml | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml index 889e798c8a..6fa9cabb37 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml @@ -108,7 +108,7 @@ public class FormElementsModel : PageModel { public SampleModel MyModel { get; set; } - + public List<SelectListItem> CityList { get; set; } = new List<SelectListItem> { new SelectListItem { Value = "NY", Text = "New York"}, @@ -260,7 +260,7 @@ public class SampleModel { public string SampleInput0 { get; set; } - + public string SampleInput1 { get; set; } public string SampleInput2 { get; set; } @@ -354,7 +354,7 @@ public class FormElementsModel : PageModel { public SampleModel MyModel { get; set; } - + public List"SelectListItem" CityList { get; set; } = new List"SelectListItem" { new SelectListItem { Value = "NY", Text = "New York"}, @@ -458,6 +458,51 @@ <option value="3">Coupe</option> </select> </div> + + + + + + +

Suppress Label Generation

+ +
+
+ +
+
+ + +

+ public class FormElementsModel : PageModel
+ {
+     public SampleModel MyModel { get; set; }
+
+     public void OnGet()
+     {
+         MyModel = new SampleModel();
+     }
+
+     public class SampleModel
+     {
+         [Required]
+         public string Name { get; set; }
+     }
+ }
+
+
+
+ +

+<abp-input asp-for="@@Model.MyModel.Name" suppress-label="true"/>
+                
+
+ +

+<div class="form-group">
+    <input type="text" id="MyModel_Name" name="MyModel.Name" value="" class="form-control ">
+    <span class="text-danger field-validation-valid" data-valmsg-for="MyModel.Name" data-valmsg-replace="true"></span>
+</div>
 
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 010/376] 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 011/376] 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 012/376] 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 013/376] 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 014/376] 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 015/376] 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 016/376] 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 017/376] 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 018/376] 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 019/376] 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 020/376] 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 021/376] 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 022/376] 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 c6cdc8d628a2ea87a4473e86cd5bdd85888d5f8d Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 10 Jul 2020 16:02:54 +0800 Subject: [PATCH 023/376] Add TestMemoryDistributedCache for better test. --- .../Volo/Abp/Caching/AbpCachingTestModule.cs | 6 +- .../Abp/Caching/TestMemoryDistributedCache.cs | 61 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/TestMemoryDistributedCache.cs diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/AbpCachingTestModule.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/AbpCachingTestModule.cs index be003431f2..9da6725fa5 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/AbpCachingTestModule.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/AbpCachingTestModule.cs @@ -1,5 +1,7 @@ using Microsoft.Extensions.Caching.Distributed; using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Modularity; namespace Volo.Abp.Caching @@ -26,6 +28,8 @@ namespace Volo.Abp.Caching option.GlobalCacheEntryOptions.SetSlidingExpiration(TimeSpan.FromMinutes(20)); }); + + context.Services.Replace(ServiceDescriptor.Singleton()); } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/TestMemoryDistributedCache.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/TestMemoryDistributedCache.cs new file mode 100644 index 0000000000..69589d97cd --- /dev/null +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/TestMemoryDistributedCache.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Caching +{ + [DisableConventionalRegistration] + public class TestMemoryDistributedCache : MemoryDistributedCache, ICacheSupportsMultipleItems + { + public TestMemoryDistributedCache(IOptions optionsAccessor) + : base(optionsAccessor) + { + } + + public TestMemoryDistributedCache(IOptions optionsAccessor, ILoggerFactory loggerFactory) + : base(optionsAccessor, loggerFactory) + { + } + + public byte[][] GetMany(IEnumerable keys) + { + var values = new List(); + foreach (var key in keys) + { + values.Add(Get(key)); + } + return values.ToArray(); + } + + public async Task GetManyAsync(IEnumerable keys, CancellationToken token = default) + { + var values = new List(); + foreach (var key in keys) + { + values.Add(await GetAsync(key, token)); + } + return values.ToArray(); + } + + public void SetMany(IEnumerable> items, DistributedCacheEntryOptions options) + { + foreach (var item in items) + { + Set(item.Key, item.Value, options); + } + } + + public async Task SetManyAsync(IEnumerable> items, DistributedCacheEntryOptions options, CancellationToken token = default) + { + foreach (var item in items) + { + await SetAsync(item.Key, item.Value, options, token); + } + } + } +} 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 024/376] 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 025/376] 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 026/376] 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 a3955f9ae28716037af77de2ec1180635320348a Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 13 Jul 2020 13:46:17 +0800 Subject: [PATCH 027/376] Introduce AbpFileExtensionContentTypeProvider. --- ...lFileSystemApplicationBuilderExtensions.cs | 20 +- .../AbpAspNetCoreContentOptions.cs | 402 +++++++++++++++++- .../AbpFileExtensionContentTypeProvider.cs | 39 ++ 3 files changed, 440 insertions(+), 21 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpFileExtensionContentTypeProvider.cs diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs index 0557c37380..da9f65059f 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs @@ -1,18 +1,22 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.VirtualFileSystem; namespace Microsoft.AspNetCore.Builder { public static class VirtualFileSystemApplicationBuilderExtensions { - public static IApplicationBuilder UseVirtualFiles(this IApplicationBuilder app) + public static IApplicationBuilder UseVirtualFiles(this IApplicationBuilder app, Action configure = null) { - return app.UseStaticFiles( - new StaticFileOptions - { - FileProvider = app.ApplicationServices.GetRequiredService() - } - ); + var staticFileOptions = new StaticFileOptions + { + FileProvider = app.ApplicationServices.GetRequiredService(), + ContentTypeProvider = app.ApplicationServices.GetRequiredService() + }; + + configure?.Invoke(staticFileOptions); + + return app.UseStaticFiles(staticFileOptions); } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpAspNetCoreContentOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpAspNetCoreContentOptions.cs index ce6e454f54..f4b7d631cc 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpAspNetCoreContentOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpAspNetCoreContentOptions.cs @@ -1,14 +1,401 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; namespace Volo.Abp.AspNetCore.VirtualFileSystem { public class AbpAspNetCoreContentOptions { + public Dictionary ContentTypeMaps { get; } + public List AllowedExtraWebContentFolders { get; } + public List AllowedExtraWebContentFileExtensions { get; } public AbpAspNetCoreContentOptions() { + ContentTypeMaps = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + {".323", "text/h323"}, + {".3g2", "video/3gpp2"}, + {".3gp2", "video/3gpp2"}, + {".3gp", "video/3gpp"}, + {".3gpp", "video/3gpp"}, + {".aac", "audio/aac"}, + {".aaf", "application/octet-stream"}, + {".aca", "application/octet-stream"}, + {".accdb", "application/msaccess"}, + {".accde", "application/msaccess"}, + {".accdt", "application/msaccess"}, + {".acx", "application/internet-property-stream"}, + {".adt", "audio/vnd.dlna.adts"}, + {".adts", "audio/vnd.dlna.adts"}, + {".afm", "application/octet-stream"}, + {".ai", "application/postscript"}, + {".aif", "audio/x-aiff"}, + {".aifc", "audio/aiff"}, + {".aiff", "audio/aiff"}, + {".appcache", "text/cache-manifest"}, + {".application", "application/x-ms-application"}, + {".art", "image/x-jg"}, + {".asd", "application/octet-stream"}, + {".asf", "video/x-ms-asf"}, + {".asi", "application/octet-stream"}, + {".asm", "text/plain"}, + {".asr", "video/x-ms-asf"}, + {".asx", "video/x-ms-asf"}, + {".atom", "application/atom+xml"}, + {".au", "audio/basic"}, + {".avi", "video/x-msvideo"}, + {".axs", "application/olescript"}, + {".bas", "text/plain"}, + {".bcpio", "application/x-bcpio"}, + {".bin", "application/octet-stream"}, + {".bmp", "image/bmp"}, + {".c", "text/plain"}, + {".cab", "application/vnd.ms-cab-compressed"}, + {".calx", "application/vnd.ms-office.calx"}, + {".cat", "application/vnd.ms-pki.seccat"}, + {".cdf", "application/x-cdf"}, + {".chm", "application/octet-stream"}, + {".class", "application/x-java-applet"}, + {".clp", "application/x-msclip"}, + {".cmx", "image/x-cmx"}, + {".cnf", "text/plain"}, + {".cod", "image/cis-cod"}, + {".cpio", "application/x-cpio"}, + {".cpp", "text/plain"}, + {".crd", "application/x-mscardfile"}, + {".crl", "application/pkix-crl"}, + {".crt", "application/x-x509-ca-cert"}, + {".csh", "application/x-csh"}, + {".css", "text/css"}, + {".csv", "application/octet-stream"}, + {".cur", "application/octet-stream"}, + {".dcr", "application/x-director"}, + {".deploy", "application/octet-stream"}, + {".der", "application/x-x509-ca-cert"}, + {".dib", "image/bmp"}, + {".dir", "application/x-director"}, + {".disco", "text/xml"}, + {".dlm", "text/dlm"}, + {".doc", "application/msword"}, + {".docm", "application/vnd.ms-word.document.macroEnabled.12"}, + {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, + {".dot", "application/msword"}, + {".dotm", "application/vnd.ms-word.template.macroEnabled.12"}, + {".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"}, + {".dsp", "application/octet-stream"}, + {".dtd", "text/xml"}, + {".dvi", "application/x-dvi"}, + {".dvr-ms", "video/x-ms-dvr"}, + {".dwf", "drawing/x-dwf"}, + {".dwp", "application/octet-stream"}, + {".dxr", "application/x-director"}, + {".eml", "message/rfc822"}, + {".emz", "application/octet-stream"}, + {".eot", "application/vnd.ms-fontobject"}, + {".eps", "application/postscript"}, + {".etx", "text/x-setext"}, + {".evy", "application/envoy"}, + {".fdf", "application/vnd.fdf"}, + {".fif", "application/fractals"}, + {".fla", "application/octet-stream"}, + {".flr", "x-world/x-vrml"}, + {".flv", "video/x-flv"}, + {".gif", "image/gif"}, + {".gtar", "application/x-gtar"}, + {".gz", "application/x-gzip"}, + {".h", "text/plain"}, + {".hdf", "application/x-hdf"}, + {".hdml", "text/x-hdml"}, + {".hhc", "application/x-oleobject"}, + {".hhk", "application/octet-stream"}, + {".hhp", "application/octet-stream"}, + {".hlp", "application/winhlp"}, + {".hqx", "application/mac-binhex40"}, + {".hta", "application/hta"}, + {".htc", "text/x-component"}, + {".htm", "text/html"}, + {".html", "text/html"}, + {".htt", "text/webviewhtml"}, + {".hxt", "text/html"}, + {".ical", "text/calendar"}, + {".icalendar", "text/calendar"}, + {".ico", "image/x-icon"}, + {".ics", "text/calendar"}, + {".ief", "image/ief"}, + {".ifb", "text/calendar"}, + {".iii", "application/x-iphone"}, + {".inf", "application/octet-stream"}, + {".ins", "application/x-internet-signup"}, + {".isp", "application/x-internet-signup"}, + {".IVF", "video/x-ivf"}, + {".jar", "application/java-archive"}, + {".java", "application/octet-stream"}, + {".jck", "application/liquidmotion"}, + {".jcz", "application/liquidmotion"}, + {".jfif", "image/pjpeg"}, + {".jpb", "application/octet-stream"}, + {".jpe", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".jpg", "image/jpeg"}, + {".js", "application/javascript"}, + {".json", "application/json"}, + {".jsx", "text/jscript"}, + {".latex", "application/x-latex"}, + {".lit", "application/x-ms-reader"}, + {".lpk", "application/octet-stream"}, + {".lsf", "video/x-la-asf"}, + {".lsx", "video/x-la-asf"}, + {".lzh", "application/octet-stream"}, + {".m13", "application/x-msmediaview"}, + {".m14", "application/x-msmediaview"}, + {".m1v", "video/mpeg"}, + {".m2ts", "video/vnd.dlna.mpeg-tts"}, + {".m3u", "audio/x-mpegurl"}, + {".m4a", "audio/mp4"}, + {".m4v", "video/mp4"}, + {".man", "application/x-troff-man"}, + {".manifest", "application/x-ms-manifest"}, + {".map", "text/plain"}, + {".markdown", "text/markdown"}, + {".md", "text/markdown"}, + {".mdb", "application/x-msaccess"}, + {".mdp", "application/octet-stream"}, + {".me", "application/x-troff-me"}, + {".mht", "message/rfc822"}, + {".mhtml", "message/rfc822"}, + {".mid", "audio/mid"}, + {".midi", "audio/mid"}, + {".mix", "application/octet-stream"}, + {".mmf", "application/x-smaf"}, + {".mno", "text/xml"}, + {".mny", "application/x-msmoney"}, + {".mov", "video/quicktime"}, + {".movie", "video/x-sgi-movie"}, + {".mp2", "video/mpeg"}, + {".mp3", "audio/mpeg"}, + {".mp4", "video/mp4"}, + {".mp4v", "video/mp4"}, + {".mpa", "video/mpeg"}, + {".mpe", "video/mpeg"}, + {".mpeg", "video/mpeg"}, + {".mpg", "video/mpeg"}, + {".mpp", "application/vnd.ms-project"}, + {".mpv2", "video/mpeg"}, + {".ms", "application/x-troff-ms"}, + {".msi", "application/octet-stream"}, + {".mso", "application/octet-stream"}, + {".mvb", "application/x-msmediaview"}, + {".mvc", "application/x-miva-compiled"}, + {".nc", "application/x-netcdf"}, + {".nsc", "video/x-ms-asf"}, + {".nws", "message/rfc822"}, + {".ocx", "application/octet-stream"}, + {".oda", "application/oda"}, + {".odc", "text/x-ms-odc"}, + {".ods", "application/oleobject"}, + {".oga", "audio/ogg"}, + {".ogg", "video/ogg"}, + {".ogv", "video/ogg"}, + {".ogx", "application/ogg"}, + {".one", "application/onenote"}, + {".onea", "application/onenote"}, + {".onetoc", "application/onenote"}, + {".onetoc2", "application/onenote"}, + {".onetmp", "application/onenote"}, + {".onepkg", "application/onenote"}, + {".osdx", "application/opensearchdescription+xml"}, + {".otf", "font/otf"}, + {".p10", "application/pkcs10"}, + {".p12", "application/x-pkcs12"}, + {".p7b", "application/x-pkcs7-certificates"}, + {".p7c", "application/pkcs7-mime"}, + {".p7m", "application/pkcs7-mime"}, + {".p7r", "application/x-pkcs7-certreqresp"}, + {".p7s", "application/pkcs7-signature"}, + {".pbm", "image/x-portable-bitmap"}, + {".pcx", "application/octet-stream"}, + {".pcz", "application/octet-stream"}, + {".pdf", "application/pdf"}, + {".pfb", "application/octet-stream"}, + {".pfm", "application/octet-stream"}, + {".pfx", "application/x-pkcs12"}, + {".pgm", "image/x-portable-graymap"}, + {".pko", "application/vnd.ms-pki.pko"}, + {".pma", "application/x-perfmon"}, + {".pmc", "application/x-perfmon"}, + {".pml", "application/x-perfmon"}, + {".pmr", "application/x-perfmon"}, + {".pmw", "application/x-perfmon"}, + {".png", "image/png"}, + {".pnm", "image/x-portable-anymap"}, + {".pnz", "image/png"}, + {".pot", "application/vnd.ms-powerpoint"}, + {".potm", "application/vnd.ms-powerpoint.template.macroEnabled.12"}, + {".potx", "application/vnd.openxmlformats-officedocument.presentationml.template"}, + {".ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12"}, + {".ppm", "image/x-portable-pixmap"}, + {".pps", "application/vnd.ms-powerpoint"}, + {".ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"}, + {".ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"}, + {".ppt", "application/vnd.ms-powerpoint"}, + {".pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"}, + {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, + {".prf", "application/pics-rules"}, + {".prm", "application/octet-stream"}, + {".prx", "application/octet-stream"}, + {".ps", "application/postscript"}, + {".psd", "application/octet-stream"}, + {".psm", "application/octet-stream"}, + {".psp", "application/octet-stream"}, + {".pub", "application/x-mspublisher"}, + {".qt", "video/quicktime"}, + {".qtl", "application/x-quicktimeplayer"}, + {".qxd", "application/octet-stream"}, + {".ra", "audio/x-pn-realaudio"}, + {".ram", "audio/x-pn-realaudio"}, + {".rar", "application/octet-stream"}, + {".ras", "image/x-cmu-raster"}, + {".rf", "image/vnd.rn-realflash"}, + {".rgb", "image/x-rgb"}, + {".rm", "application/vnd.rn-realmedia"}, + {".rmi", "audio/mid"}, + {".roff", "application/x-troff"}, + {".rpm", "audio/x-pn-realaudio-plugin"}, + {".rtf", "application/rtf"}, + {".rtx", "text/richtext"}, + {".scd", "application/x-msschedule"}, + {".sct", "text/scriptlet"}, + {".sea", "application/octet-stream"}, + {".setpay", "application/set-payment-initiation"}, + {".setreg", "application/set-registration-initiation"}, + {".sgml", "text/sgml"}, + {".sh", "application/x-sh"}, + {".shar", "application/x-shar"}, + {".sit", "application/x-stuffit"}, + {".sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12"}, + {".sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide"}, + {".smd", "audio/x-smd"}, + {".smi", "application/octet-stream"}, + {".smx", "audio/x-smd"}, + {".smz", "audio/x-smd"}, + {".snd", "audio/basic"}, + {".snp", "application/octet-stream"}, + {".spc", "application/x-pkcs7-certificates"}, + {".spl", "application/futuresplash"}, + {".spx", "audio/ogg"}, + {".src", "application/x-wais-source"}, + {".ssm", "application/streamingmedia"}, + {".sst", "application/vnd.ms-pki.certstore"}, + {".stl", "application/vnd.ms-pki.stl"}, + {".sv4cpio", "application/x-sv4cpio"}, + {".sv4crc", "application/x-sv4crc"}, + {".svg", "image/svg+xml"}, + {".svgz", "image/svg+xml"}, + {".swf", "application/x-shockwave-flash"}, + {".t", "application/x-troff"}, + {".tar", "application/x-tar"}, + {".tcl", "application/x-tcl"}, + {".tex", "application/x-tex"}, + {".texi", "application/x-texinfo"}, + {".texinfo", "application/x-texinfo"}, + {".tgz", "application/x-compressed"}, + {".thmx", "application/vnd.ms-officetheme"}, + {".thn", "application/octet-stream"}, + {".tif", "image/tiff"}, + {".tiff", "image/tiff"}, + {".toc", "application/octet-stream"}, + {".tr", "application/x-troff"}, + {".trm", "application/x-msterminal"}, + {".ts", "video/vnd.dlna.mpeg-tts"}, + {".tsv", "text/tab-separated-values"}, + {".ttc", "application/x-font-ttf"}, + {".ttf", "application/x-font-ttf"}, + {".tts", "video/vnd.dlna.mpeg-tts"}, + {".txt", "text/plain"}, + {".u32", "application/octet-stream"}, + {".uls", "text/iuls"}, + {".ustar", "application/x-ustar"}, + {".vbs", "text/vbscript"}, + {".vcf", "text/x-vcard"}, + {".vcs", "text/plain"}, + {".vdx", "application/vnd.ms-visio.viewer"}, + {".vml", "text/xml"}, + {".vsd", "application/vnd.visio"}, + {".vss", "application/vnd.visio"}, + {".vst", "application/vnd.visio"}, + {".vsto", "application/x-ms-vsto"}, + {".vsw", "application/vnd.visio"}, + {".vsx", "application/vnd.visio"}, + {".vtx", "application/vnd.visio"}, + {".wasm", "application/wasm"}, + {".wav", "audio/wav"}, + {".wax", "audio/x-ms-wax"}, + {".wbmp", "image/vnd.wap.wbmp"}, + {".wcm", "application/vnd.ms-works"}, + {".wdb", "application/vnd.ms-works"}, + {".webm", "video/webm"}, + {".webp", "image/webp"}, + {".wks", "application/vnd.ms-works"}, + {".wm", "video/x-ms-wm"}, + {".wma", "audio/x-ms-wma"}, + {".wmd", "application/x-ms-wmd"}, + {".wmf", "application/x-msmetafile"}, + {".wml", "text/vnd.wap.wml"}, + {".wmlc", "application/vnd.wap.wmlc"}, + {".wmls", "text/vnd.wap.wmlscript"}, + {".wmlsc", "application/vnd.wap.wmlscriptc"}, + {".wmp", "video/x-ms-wmp"}, + {".wmv", "video/x-ms-wmv"}, + {".wmx", "video/x-ms-wmx"}, + {".wmz", "application/x-ms-wmz"}, + {".woff", "application/font-woff"}, // https://www.w3.org/TR/WOFF/#appendix-b + {".woff2", "font/woff2"}, // https://www.w3.org/TR/WOFF2/#IMT + {".wps", "application/vnd.ms-works"}, + {".wri", "application/x-mswrite"}, + {".wrl", "x-world/x-vrml"}, + {".wrz", "x-world/x-vrml"}, + {".wsdl", "text/xml"}, + {".wtv", "video/x-ms-wtv"}, + {".wvx", "video/x-ms-wvx"}, + {".x", "application/directx"}, + {".xaf", "x-world/x-vrml"}, + {".xaml", "application/xaml+xml"}, + {".xap", "application/x-silverlight-app"}, + {".xbap", "application/x-ms-xbap"}, + {".xbm", "image/x-xbitmap"}, + {".xdr", "text/plain"}, + {".xht", "application/xhtml+xml"}, + {".xhtml", "application/xhtml+xml"}, + {".xla", "application/vnd.ms-excel"}, + {".xlam", "application/vnd.ms-excel.addin.macroEnabled.12"}, + {".xlc", "application/vnd.ms-excel"}, + {".xlm", "application/vnd.ms-excel"}, + {".xls", "application/vnd.ms-excel"}, + {".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"}, + {".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12"}, + {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, + {".xlt", "application/vnd.ms-excel"}, + {".xltm", "application/vnd.ms-excel.template.macroEnabled.12"}, + {".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"}, + {".xlw", "application/vnd.ms-excel"}, + {".xml", "text/xml"}, + {".xof", "x-world/x-vrml"}, + {".xpm", "image/x-xpixmap"}, + {".xps", "application/vnd.ms-xpsdocument"}, + {".xsd", "text/xml"}, + {".xsf", "text/xml"}, + {".xsl", "text/xml"}, + {".xslt", "text/xml"}, + {".xsn", "application/octet-stream"}, + {".xtp", "application/octet-stream"}, + {".xwd", "image/x-xwindowdump"}, + {".z", "application/x-compress"}, + {".zip", "application/x-zip-compressed"}, + }; + AllowedExtraWebContentFolders = new List { "/Pages", @@ -16,18 +403,7 @@ namespace Volo.Abp.AspNetCore.VirtualFileSystem "/Themes" }; - AllowedExtraWebContentFileExtensions = new List - { - ".js", - ".css", - ".png", - ".jpg", - ".jpeg", - ".woff", - ".woff2", - ".tff", - ".otf" - }; + AllowedExtraWebContentFileExtensions = ContentTypeMaps.Select(x => x.Key).ToList(); } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpFileExtensionContentTypeProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpFileExtensionContentTypeProvider.cs new file mode 100644 index 0000000000..82ca1c5539 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpFileExtensionContentTypeProvider.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.VirtualFileSystem +{ + public class AbpFileExtensionContentTypeProvider : IContentTypeProvider, ITransientDependency + { + protected AbpAspNetCoreContentOptions Options { get; } + + public AbpFileExtensionContentTypeProvider(IOptions abpAspNetCoreContentOptions) + { + Options = abpAspNetCoreContentOptions.Value; + } + + public bool TryGetContentType(string subpath, out string contentType) + { + var extension = GetExtension(subpath); + if (extension == null) + { + contentType = null; + return false; + } + + return Options.ContentTypeMaps.TryGetValue(extension, out contentType); + } + + protected virtual string GetExtension(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + return null; + } + + var index = path.LastIndexOf('.'); + return index < 0 ? null : path.Substring(index); + } + } +} From a86e58bdead9e996999e49d81c91460e3b909c48 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Tue, 14 Jul 2020 12:15:52 +0300 Subject: [PATCH 028/376] cli: rename nightly preview commands --- docs/en/CLI.md | 8 ++++---- .../Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs | 4 ++-- ...eCommand.cs => SwitchFromNightlyToStableCommand.cs} | 8 ++++---- ...htlyPreviewCommand.cs => SwitchToNightlyCommand.cs} | 10 +++++----- 4 files changed, 15 insertions(+), 15 deletions(-) rename framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/{SwitchStableCommand.cs => SwitchFromNightlyToStableCommand.cs} (81%) rename framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/{SwitchNightlyPreviewCommand.cs => SwitchToNightlyCommand.cs} (80%) diff --git a/docs/en/CLI.md b/docs/en/CLI.md index 8551d64505..df31e91d71 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -196,12 +196,12 @@ abp generate-proxy --apiUrl https://localhost:44305 --ui angular --module all ### switch-to-preview -You can use this command to switch your project to latest preview version of the ABP framework packages. +You can use this command to switch your project to latest **nightly** preview version of the ABP framework packages. Usage: ````bash -abp switch-to-preview [options] +abp switch-to-nightly [options] ```` #### Options @@ -210,12 +210,12 @@ abp switch-to-preview [options] ### switch-to-stable -If you're using the ABP Framework preview packages, you can switch back to stable version using this command. +If you're using the ABP Framework **nightly** preview packages, you can switch back to stable version using this command. Usage: ````bash -abp switch-to-stable [options] +abp switch-from-nightly-to-stable [options] ```` #### Options diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index dbffa820c8..4e883ef4bb 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -31,8 +31,8 @@ namespace Volo.Abp.Cli options.Commands["logout"] = typeof(LogoutCommand); options.Commands["generate-proxy"] = typeof(GenerateProxyCommand); options.Commands["suite"] = typeof(SuiteCommand); - options.Commands["switch-to-preview"] = typeof(SwitchNightlyPreviewCommand); - options.Commands["switch-to-stable"] = typeof(SwitchStableCommand); + options.Commands["switch-to-nightly"] = typeof(SwitchToNightlyCommand); + options.Commands["switch-from-nightly-to-stable"] = typeof(SwitchFromNightlyToStableCommand); options.Commands["translate"] = typeof(TranslateCommand); }); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchStableCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchFromNightlyToStableCommand.cs similarity index 81% rename from framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchStableCommand.cs rename to framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchFromNightlyToStableCommand.cs index 54db7bc082..a4acf871d8 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchStableCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchFromNightlyToStableCommand.cs @@ -6,11 +6,11 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Cli.Commands { - public class SwitchStableCommand : IConsoleCommand, ITransientDependency + public class SwitchFromNightlyToStableCommand : IConsoleCommand, ITransientDependency { private readonly PackageSourceSwitcher _packageSourceSwitcher; - public SwitchStableCommand(PackageSourceSwitcher packageSourceSwitcher) + public SwitchFromNightlyToStableCommand(PackageSourceSwitcher packageSourceSwitcher) { _packageSourceSwitcher = packageSourceSwitcher; } @@ -26,7 +26,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine(""); sb.AppendLine("Usage:"); - sb.AppendLine(" abp switch-to-stable [options]"); + sb.AppendLine(" abp switch-from-nightly-to-stable [options]"); sb.AppendLine(""); sb.AppendLine("Options:"); sb.AppendLine("-sd|--solution-directory"); @@ -41,4 +41,4 @@ namespace Volo.Abp.Cli.Commands return "Switches packages to stable ABP version from preview version."; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchNightlyPreviewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToNightlyCommand.cs similarity index 80% rename from framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchNightlyPreviewCommand.cs rename to framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToNightlyCommand.cs index 883ac4db2f..3a22e004c3 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchNightlyPreviewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToNightlyCommand.cs @@ -6,11 +6,11 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Cli.Commands { - public class SwitchNightlyPreviewCommand : IConsoleCommand, ITransientDependency + public class SwitchToNightlyCommand : IConsoleCommand, ITransientDependency { private readonly PackageSourceSwitcher _packageSourceSwitcher; - public SwitchNightlyPreviewCommand(PackageSourceSwitcher packageSourceSwitcher) + public SwitchToNightlyCommand(PackageSourceSwitcher packageSourceSwitcher) { _packageSourceSwitcher = packageSourceSwitcher; } @@ -26,8 +26,8 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine(""); sb.AppendLine("Usage:"); - sb.AppendLine(" abp switch-to-preview [options]"); - sb.AppendLine(""); + sb.AppendLine(" abp switch-to-nightly [options]"); + sb.AppendLine(""); sb.AppendLine("Options:"); sb.AppendLine("-sd|--solution-directory"); sb.AppendLine(""); @@ -41,4 +41,4 @@ namespace Volo.Abp.Cli.Commands return "Switches packages to nightly preview ABP version."; } } -} \ No newline at end of file +} From 31c992fe1749320f1a945e75c2063e3c7b13c83b Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Tue, 14 Jul 2020 14:02:14 +0300 Subject: [PATCH 029/376] Cli: update option for rc previews --- docs/en/CLI.md | 4 +- .../Volo/Abp/Cli/AbpCliCoreModule.cs | 6 +- .../Cli/Commands/SwitchToNightlyCommand.cs | 8 +-- .../Cli/Commands/SwitchToPreviewCommand.cs | 44 +++++++++++++++ ...bleCommand.cs => SwitchToStableCommand.cs} | 10 ++-- .../Volo/Abp/Cli/NuGet/NuGetService.cs | 4 +- ...eSwitcher.cs => PackagePreviewSwitcher.cs} | 24 ++++++-- .../VoloNugetPackagesVersionUpdater.cs | 55 ++++++++++++++----- 8 files changed, 122 insertions(+), 33 deletions(-) create mode 100644 framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToPreviewCommand.cs rename framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/{SwitchFromNightlyToStableCommand.cs => SwitchToStableCommand.cs} (72%) rename framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/{PackageSourceSwitcher.cs => PackagePreviewSwitcher.cs} (80%) diff --git a/docs/en/CLI.md b/docs/en/CLI.md index df31e91d71..0b26806fd8 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -210,12 +210,12 @@ abp switch-to-nightly [options] ### switch-to-stable -If you're using the ABP Framework **nightly** preview packages, you can switch back to stable version using this command. +If you're using the ABP Framework preview packages, you can switch back to latest stable version using this command. Usage: ````bash -abp switch-from-nightly-to-stable [options] +abp switch-to-stable [options] ```` #### Options diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index 4e883ef4bb..0244d46c47 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -1,5 +1,4 @@ -using System; -using System.Text; +using System.Text; using Volo.Abp.Cli.Commands; using Volo.Abp.Domain; using Volo.Abp.IdentityModel; @@ -31,8 +30,9 @@ namespace Volo.Abp.Cli options.Commands["logout"] = typeof(LogoutCommand); options.Commands["generate-proxy"] = typeof(GenerateProxyCommand); options.Commands["suite"] = typeof(SuiteCommand); + options.Commands["switch-to-preview"] = typeof(SwitchToPreviewCommand); + options.Commands["switch-to-stable"] = typeof(SwitchToStableCommand); options.Commands["switch-to-nightly"] = typeof(SwitchToNightlyCommand); - options.Commands["switch-from-nightly-to-stable"] = typeof(SwitchFromNightlyToStableCommand); options.Commands["translate"] = typeof(TranslateCommand); }); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToNightlyCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToNightlyCommand.cs index 3a22e004c3..473489990f 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToNightlyCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToNightlyCommand.cs @@ -8,16 +8,16 @@ namespace Volo.Abp.Cli.Commands { public class SwitchToNightlyCommand : IConsoleCommand, ITransientDependency { - private readonly PackageSourceSwitcher _packageSourceSwitcher; + private readonly PackagePreviewSwitcher _packagePreviewSwitcher; - public SwitchToNightlyCommand(PackageSourceSwitcher packageSourceSwitcher) + public SwitchToNightlyCommand(PackagePreviewSwitcher packagePreviewSwitcher) { - _packageSourceSwitcher = packageSourceSwitcher; + _packagePreviewSwitcher = packagePreviewSwitcher; } public async Task ExecuteAsync(CommandLineArgs commandLineArgs) { - await _packageSourceSwitcher.SwitchToPreview(commandLineArgs); + await _packagePreviewSwitcher.SwitchToNightlyPreview(commandLineArgs); } public string GetUsageInfo() diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToPreviewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToPreviewCommand.cs new file mode 100644 index 0000000000..e6c401a8b5 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToPreviewCommand.cs @@ -0,0 +1,44 @@ +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Cli.Args; +using Volo.Abp.Cli.ProjectModification; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.Commands +{ + public class SwitchToPreviewCommand : IConsoleCommand, ITransientDependency + { + private readonly PackagePreviewSwitcher _packagePreviewSwitcher; + + public SwitchToPreviewCommand(PackagePreviewSwitcher packagePreviewSwitcher) + { + _packagePreviewSwitcher = packagePreviewSwitcher; + } + + public async Task ExecuteAsync(CommandLineArgs commandLineArgs) + { + await _packagePreviewSwitcher.SwitchToPreview(commandLineArgs); + } + + public string GetUsageInfo() + { + var sb = new StringBuilder(); + + sb.AppendLine(""); + sb.AppendLine("Usage:"); + sb.AppendLine(" abp switch-to-preview [options]"); + sb.AppendLine(""); + sb.AppendLine("Options:"); + sb.AppendLine("-sd|--solution-directory"); + sb.AppendLine(""); + sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); + + return sb.ToString(); + } + + public string GetShortDescription() + { + return "Switches packages to preview ABP version."; + } + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchFromNightlyToStableCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToStableCommand.cs similarity index 72% rename from framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchFromNightlyToStableCommand.cs rename to framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToStableCommand.cs index a4acf871d8..d425aed4e5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchFromNightlyToStableCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToStableCommand.cs @@ -6,18 +6,18 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Cli.Commands { - public class SwitchFromNightlyToStableCommand : IConsoleCommand, ITransientDependency + public class SwitchToStableCommand : IConsoleCommand, ITransientDependency { - private readonly PackageSourceSwitcher _packageSourceSwitcher; + private readonly PackagePreviewSwitcher _packagePreviewSwitcher; - public SwitchFromNightlyToStableCommand(PackageSourceSwitcher packageSourceSwitcher) + public SwitchToStableCommand(PackagePreviewSwitcher packagePreviewSwitcher) { - _packageSourceSwitcher = packageSourceSwitcher; + _packagePreviewSwitcher = packagePreviewSwitcher; } public async Task ExecuteAsync(CommandLineArgs commandLineArgs) { - await _packageSourceSwitcher.SwitchToStable(commandLineArgs); + await _packagePreviewSwitcher.SwitchToStable(commandLineArgs); } public string GetUsageInfo() diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs index 0fd35582bf..8b58ad2d9a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs @@ -39,7 +39,7 @@ namespace Volo.Abp.Cli.NuGet Logger = NullLogger.Instance; } - public async Task GetLatestVersionOrNullAsync(string packageId, bool includePreviews = false, bool includeNightly = false) + public async Task GetLatestVersionOrNullAsync(string packageId, bool includePreviews = false, bool includeNightly = false, bool includeReleaseCandidates = false) { if (AuthService.IsLoggedIn()) { @@ -80,7 +80,7 @@ namespace Volo.Abp.Cli.NuGet .Versions .Select(SemanticVersion.Parse); - if (!includePreviews && !includeNightly) + if (!includePreviews && !includeNightly && !includeReleaseCandidates) { versions = versions.Where(x => !x.IsPrerelease); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceSwitcher.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs similarity index 80% rename from framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceSwitcher.cs rename to framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs index f6c89be039..cccd468a25 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceSwitcher.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs @@ -9,26 +9,41 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Cli.ProjectModification { - public class PackageSourceSwitcher : ITransientDependency + public class PackagePreviewSwitcher : ITransientDependency { private readonly PackageSourceAdder _packageSourceAdder; private readonly NpmPackagesUpdater _npmPackagesUpdater; private readonly VoloNugetPackagesVersionUpdater _nugetPackagesVersionUpdater; - public ILogger Logger { get; set; } + public ILogger Logger { get; set; } - public PackageSourceSwitcher(PackageSourceAdder packageSourceAdder, + public PackagePreviewSwitcher(PackageSourceAdder packageSourceAdder, NpmPackagesUpdater npmPackagesUpdater, VoloNugetPackagesVersionUpdater nugetPackagesVersionUpdater) { _packageSourceAdder = packageSourceAdder; _npmPackagesUpdater = npmPackagesUpdater; _nugetPackagesVersionUpdater = nugetPackagesVersionUpdater; - Logger = NullLogger.Instance; + Logger = NullLogger.Instance; } public async Task SwitchToPreview(CommandLineArgs commandLineArgs) { + var solutionPath = GetSolutionPath(commandLineArgs); + var solutionFolder = GetSolutionFolder(commandLineArgs); + + await _nugetPackagesVersionUpdater.UpdateSolutionAsync( + solutionPath, + includeReleaseCandidates: true); + + await _npmPackagesUpdater.Update( + solutionFolder, + true); + } + + public async Task SwitchToNightlyPreview(CommandLineArgs commandLineArgs) + { + // TODO: Remove this when switched to stable _packageSourceAdder.Add("ABP Nightly", "https://www.myget.org/F/abp-nightly/api/v3/index.json"); var solutionPath = GetSolutionPath(commandLineArgs); @@ -51,6 +66,7 @@ namespace Volo.Abp.Cli.ProjectModification await _nugetPackagesVersionUpdater.UpdateSolutionAsync( solutionPath, false, + false, true); await _npmPackagesUpdater.Update( diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs index 9661dceddd..21e02faac4 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs @@ -25,23 +25,30 @@ namespace Volo.Abp.Cli.ProjectModification Logger = NullLogger.Instance; } - public async Task UpdateSolutionAsync(string solutionPath, bool includePreviews = false, bool switchToStable = false, bool checkAll = false) + public async Task UpdateSolutionAsync(string solutionPath, bool includePreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, bool checkAll = false) { var projectPaths = ProjectFinder.GetProjectFiles(solutionPath); if (checkAll) { - Task.WaitAll(projectPaths.Select(projectPath => UpdateInternalAsync(projectPath, includePreviews, switchToStable)).ToArray()); + Task.WaitAll(projectPaths.Select(projectPath => UpdateInternalAsync(projectPath, includePreviews, includeReleaseCandidates, switchToStable)).ToArray()); } else { - var latestVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core"); + var latestVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates : includeReleaseCandidates); + var latestReleaseCandidateVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates : true); var latestVersionFromMyGet = await GetLatestVersionFromMyGet("Volo.Abp.Core"); async Task UpdateAsync(string filePath) { var fileContent = File.ReadAllText(filePath); - var updatedContent = await UpdateVoloPackagesAsync(fileContent, includePreviews, switchToStable, latestVersionFromNuget, latestVersionFromMyGet); + var updatedContent = await UpdateVoloPackagesAsync(fileContent, + includePreviews, + includeReleaseCandidates, + switchToStable, + latestVersionFromNuget, + latestReleaseCandidateVersionFromNuget, + latestVersionFromMyGet); File.WriteAllText(filePath, updatedContent); } @@ -50,33 +57,47 @@ namespace Volo.Abp.Cli.ProjectModification } } - public async Task UpdateProjectAsync(string projectPath, bool includePreviews = false, bool switchToStable = false, bool checkAll = false) + public async Task UpdateProjectAsync(string projectPath, bool includeNightlyPreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, bool checkAll = false) { if (checkAll) { - await UpdateInternalAsync(projectPath, includePreviews, switchToStable); + await UpdateInternalAsync(projectPath, includeNightlyPreviews, includeReleaseCandidates, switchToStable); } else { var latestVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core"); + var latestReleaseCandidateVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates : true); var latestVersionFromMyGet = await GetLatestVersionFromMyGet("Volo.Abp.Core"); var fileContent = File.ReadAllText(projectPath); - var updatedContent = await UpdateVoloPackagesAsync(fileContent, includePreviews, switchToStable, latestVersionFromNuget, latestVersionFromMyGet); + + var updatedContent = await UpdateVoloPackagesAsync(fileContent, + includeNightlyPreviews, + includeReleaseCandidates, + switchToStable, + latestVersionFromNuget, + latestReleaseCandidateVersionFromNuget, + latestVersionFromMyGet); File.WriteAllText(projectPath, updatedContent); } } - protected virtual async Task UpdateInternalAsync(string projectPath, bool includePreviews = false, bool switchToStable = false) + protected virtual async Task UpdateInternalAsync(string projectPath, bool includeNightlyPreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false) { var fileContent = File.ReadAllText(projectPath); - var updatedContent = await UpdateVoloPackagesAsync(fileContent, includePreviews, switchToStable); + var updatedContent = await UpdateVoloPackagesAsync(fileContent, includeNightlyPreviews, includeReleaseCandidates, switchToStable); File.WriteAllText(projectPath, updatedContent); } - private async Task UpdateVoloPackagesAsync(string content, bool includePreviews = false, bool switchToStable = false, SemanticVersion latestNugetVersion = null, string latestMyGetVersion = null) + private async Task UpdateVoloPackagesAsync(string content, + bool includeNightlyPreviews = false, + bool includeReleaseCandidates = false, + bool switchToStable = false, + SemanticVersion latestNugetVersion = null, + SemanticVersion latestNugetReleaseCandidateVersion = null, + string latestMyGetVersion = null) { string packageId = null; @@ -108,7 +129,7 @@ namespace Volo.Abp.Cli.ProjectModification Logger.LogDebug("Checking package: \"{0}\" - Current version: {1}", packageId, currentSemanticVersion); - if (includePreviews || (currentVersion.Contains("-preview") && !switchToStable)) + if ((includeNightlyPreviews || (currentVersion.Contains("-preview") && !switchToStable)) && !includeReleaseCandidates) { var latestVersion = latestMyGetVersion ?? await GetLatestVersionFromMyGet(packageId); @@ -124,9 +145,17 @@ namespace Volo.Abp.Cli.ProjectModification } else { - var latestVersion = latestNugetVersion ?? await _nuGetService.GetLatestVersionOrNullAsync(packageId); + SemanticVersion latestVersion; + if (currentSemanticVersion.IsPrerelease && !switchToStable) + { + latestVersion = latestNugetReleaseCandidateVersion ?? await _nuGetService.GetLatestVersionOrNullAsync(packageId, true); + } + else + { + latestVersion = latestNugetVersion ?? await _nuGetService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: includeReleaseCandidates); + } - if (latestVersion != null && (currentVersion.Contains("-preview") || currentSemanticVersion < latestVersion)) + if (latestVersion != null && (currentSemanticVersion.IsPrerelease || currentSemanticVersion < latestVersion)) { Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, currentSemanticVersion.ToString(), latestVersion.ToString()); versionAttribute.Value = latestVersion.ToString(); From a04a07a55d51c4c78f734312b162cf5159cf2058 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Tue, 14 Jul 2020 16:46:11 +0300 Subject: [PATCH 030/376] Cli: GetSourceCommand & NewCommand --preview option --- docs/en/CLI.md | 1 + .../Volo/Abp/Cli/CliService.cs | 2 +- .../Volo/Abp/Cli/Commands/GetSourceCommand.cs | 8 +++++++- .../Volo/Abp/Cli/Commands/NewCommand.cs | 12 +++++++++++ .../ProjectBuilding/AbpIoSourceCodeStore.cs | 20 +++++++++++++------ .../Cli/ProjectBuilding/ISourceCodeStore.cs | 5 +++-- .../ProjectBuilding/ModuleProjectBuilder.cs | 4 +++- .../ProjectBuilding/TemplateProjectBuilder.cs | 4 +++- 8 files changed, 44 insertions(+), 12 deletions(-) diff --git a/docs/en/CLI.md b/docs/en/CLI.md index 0b26806fd8..f7b5ab88aa 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -90,6 +90,7 @@ abp new Acme.BookStore * **`console`**: [Console template](Startup-Templates/Console.md). * `--output-folder` or `-o`: Specifies the output folder. Default value is the current directory. * `--version` or `-v`: Specifies the ABP & template version. It can be a [release tag](https://github.com/abpframework/abp/releases) or a [branch name](https://github.com/abpframework/abp/branches). Uses the latest release if not specified. Most of the times, you will want to use the latest version. +* `--preview`: Use latest pre-release version (Only if `--version ` is not specified and there is at least one pre-release after latest stable version). * `--template-source` or `-ts`: Specifies a custom template source to use to build the project. Local and network sources can be used(Like `D:\local-template` or `https://.../my-template-file.zip`). * `--create-solution-folder` or `-csf`: Specifies if the project will be in a new folder in the output folder or directly the output folder. * `--connection-string` or `-cs`: Overwrites the default connection strings in all `appsettings.json` files. The default connection string is `Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true` for EF Core and it is configured to use the SQL Server. If you want to use the EF Core, but need to change the DBMS, you can change it as [described here](Entity-Framework-Core-Other-DBMS.md) (after creating the solution). diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs index 436e169aad..ef6eb79042 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs @@ -158,7 +158,7 @@ namespace Volo.Abp.Cli return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli"); case UpdateChannel.Prerelease: - return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includePreviews: true); + return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeReleaseCandidates: true); case UpdateChannel.Nightly: return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs index 0a6155fa67..7cda59b999 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs @@ -61,7 +61,7 @@ namespace Volo.Abp.Cli.Commands } commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command); - + await _sourceCodeDownloadService.DownloadAsync( commandLineArgs.Target, outputFolder, version, gitHubAbpLocalRepositoryPath, gitHubVoloLocalRepositoryPath, commandLineArgs.Options); } @@ -99,6 +99,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine(""); sb.AppendLine("-o|--output-folder (default: current folder)"); sb.AppendLine("-v|--version (default: latest version)"); + sb.AppendLine("--preview (Use latest pre-release version if there is at least one pre-release after latest stable version)"); sb.AppendLine(""); sb.AppendLine("Examples:"); sb.AppendLine(""); @@ -138,6 +139,11 @@ namespace Volo.Abp.Cli.Commands public const string Short = "v"; public const string Long = "version"; } + + public static class Preview + { + public const string Long = "preview"; + } } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index 8a6d944226..4a713ceb9e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -62,6 +62,12 @@ namespace Volo.Abp.Cli.Commands Logger.LogInformation("Tiered: yes"); } + var preview = commandLineArgs.Options.ContainsKey(Options.Preview.Long); + if (preview) + { + Logger.LogInformation("Preview: yes if any exist for next version."); + } + var databaseProvider = GetDatabaseProvider(commandLineArgs); if (databaseProvider != DatabaseProvider.NotSpecified) { @@ -218,6 +224,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine("-d|--database-provider (if supported by the template)"); sb.AppendLine("-o|--output-folder (default: current folder)"); sb.AppendLine("-v|--version (default: latest version)"); + sb.AppendLine("--preview (Use latest pre-release version if there is at least one pre-release after latest stable version)"); sb.AppendLine("-ts|--template-source (your local or network abp template source)"); sb.AppendLine("-csf|--create-solution-folder (default: true)"); sb.AppendLine("-cs|--connection-string (your database connection string)"); @@ -369,6 +376,11 @@ namespace Volo.Abp.Cli.Commands { public const string Long = "tiered"; } + + public static class Preview + { + public const string Long = "preview"; + } } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs index f221186636..106d7b5bcc 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs @@ -52,10 +52,11 @@ namespace Volo.Abp.Cli.ProjectBuilding string name, string type, string version = null, - string templateSource = null) + string templateSource = null, + bool includePreReleases = false) { DirectoryHelper.CreateIfNotExists(CliPaths.TemplateCache); - var latestVersion = version ?? await GetLatestSourceCodeVersionAsync(name, type); + var latestVersion = version ?? await GetLatestSourceCodeVersionAsync(name, type, null, includePreReleases); if (version == null) { @@ -110,7 +111,8 @@ namespace Volo.Abp.Cli.ProjectBuilding Name = name, Type = type, TemplateSource = templateSource, - Version = version + Version = version, + IncludePreReleases = includePreReleases } ); @@ -122,7 +124,7 @@ namespace Volo.Abp.Cli.ProjectBuilding return new TemplateFile(fileContent, version, latestVersion, nugetVersion); } - private async Task GetLatestSourceCodeVersionAsync(string name, string type, string url = null) + private async Task GetLatestSourceCodeVersionAsync(string name, string type, string url = null, bool includePreReleases = false) { if (url == null) { @@ -137,7 +139,7 @@ namespace Volo.Abp.Cli.ProjectBuilding url, new StringContent( JsonSerializer.Serialize( - new GetLatestSourceCodeVersionDto { Name = name } + new GetLatestSourceCodeVersionDto { Name = name, IncludePreReleases = includePreReleases } ), Encoding.UTF8, MimeTypes.Application.Json @@ -171,7 +173,7 @@ namespace Volo.Abp.Cli.ProjectBuilding url, new StringContent( JsonSerializer.Serialize( - new GetTemplateNugetVersionDto { Name = name, Version = version } + new GetTemplateNugetVersionDto { Name = name, Version = version} ), Encoding.UTF8, MimeTypes.Application.Json @@ -260,11 +262,15 @@ namespace Volo.Abp.Cli.ProjectBuilding public string Type { get; set; } public string TemplateSource { get; set; } + + public bool IncludePreReleases { get; set; } } public class GetLatestSourceCodeVersionDto { public string Name { get; set; } + + public bool IncludePreReleases { get; set; } } public class GetTemplateNugetVersionDto @@ -272,6 +278,8 @@ namespace Volo.Abp.Cli.ProjectBuilding public string Name { get; set; } public string Version { get; set; } + + public bool IncludePreReleases { get; set; } } public class GetVersionResultDto diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ISourceCodeStore.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ISourceCodeStore.cs index de082d4bcf..af03a6095b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ISourceCodeStore.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ISourceCodeStore.cs @@ -9,7 +9,8 @@ namespace Volo.Abp.Cli.ProjectBuilding string name, string type, [CanBeNull] string version = null, - [CanBeNull] string templateSource = null + [CanBeNull] string templateSource = null, + bool includePreReleases = false ); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs index 6a7132769a..17b9585f16 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs @@ -48,7 +48,9 @@ namespace Volo.Abp.Cli.ProjectBuilding var templateFile = await SourceCodeStore.GetAsync( args.TemplateName, SourceCodeTypes.Module, - args.Version + args.Version, + null, + args.ExtraProperties.ContainsKey(GetSourceCommand.Options.Preview.Long) ); var apiKeyResult = await ApiKeyService.GetApiKeyOrNullAsync(); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs index e8ddc804c2..02b26eba39 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs @@ -57,7 +57,8 @@ namespace Volo.Abp.Cli.ProjectBuilding args.TemplateName, SourceCodeTypes.Template, args.Version, - args.TemplateSource + args.TemplateSource, + args.ExtraProperties.ContainsKey(NewCommand.Options.Preview.Long) ); DeveloperApiKeyResult apiKeyResult = null; @@ -119,6 +120,7 @@ namespace Volo.Abp.Cli.ProjectBuilding var options = args.ExtraProperties .Where(x => !x.Key.Equals(CliConsts.Command, StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.Key.Equals(NewCommand.Options.Tiered.Long, StringComparison.InvariantCultureIgnoreCase)) + .Where(x => !x.Key.Equals(NewCommand.Options.Preview.Long, StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.Key.Equals(NewCommand.Options.DatabaseProvider.Long, StringComparison.InvariantCultureIgnoreCase) && !x.Key.Equals(NewCommand.Options.DatabaseProvider.Short, StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.Key.Equals(NewCommand.Options.OutputFolder.Long, StringComparison.InvariantCultureIgnoreCase) && From 9fcc3a123ada4d3f5f39a6dd1c9b6cd5656abc21 Mon Sep 17 00:00:00 2001 From: Richard Forrest Date: Wed, 15 Jul 2020 10:43:05 +0100 Subject: [PATCH 031/376] Add details on the correct use of unit of work in event handlers --- docs/en/Distributed-Event-Bus.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/en/Distributed-Event-Bus.md b/docs/en/Distributed-Event-Bus.md index 947b0f3142..0f2900e988 100644 --- a/docs/en/Distributed-Event-Bus.md +++ b/docs/en/Distributed-Event-Bus.md @@ -178,8 +178,11 @@ That's all. You can inject any service and perform any required logic here. A single event handler class can **subscribe to multiple events** but implementing the `IDistributedEventHandler` interface for each event type. +In your handler if you call a methods on a Repository you may find that you get an `ObjectDisposedException` being thrown. This will be because the unit of work being used by the Repository has been disposed in another context e.g. an ASP.net controller action. You will need to create a specific unit of work for your `HandleEventAsync` method. You can either use the `IUnitOfWorkManager.Begin` method or use the `UnitOfWorkAttribute` on the method. See the [Unit of work document](Unit-of-work.md) for more details. + > The handler class must be registered to the dependency injection (DI). The sample above uses the `ITransientDependency` to accomplish it. See the [DI document](Dependency-Injection.md) for more options. + ## Pre-Defined Events ABP Framework **automatically publishes** distributed events for **create, update and delete** operations for an [entity](Entities.md) once you configure it. From df11564ac1e5b659407734c8c061b00cfed5217a Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Thu, 16 Jul 2020 11:18:35 +0300 Subject: [PATCH 032/376] cli: add-package version option --- .../Volo/Abp/Cli/Commands/AddModuleCommand.cs | 3 +- .../Abp/Cli/Commands/AddPackageCommand.cs | 14 ++++++- .../ProjectNugetPackageAdder.cs | 40 ++++++++++++++----- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs index b37f67fd1a..5e690d8bb0 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs @@ -75,6 +75,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine(" -s|--solution Specify the solution file explicitly."); sb.AppendLine(" --skip-db-migrations Specify if a new migration will be added or not."); sb.AppendLine(" -sp|--startup-project Relative path to the project folder of the startup project. Default value is the current folder."); + sb.AppendLine(" -v|--version Specify the version of the module. Default is your project's ABP version."); sb.AppendLine(""); sb.AppendLine("Examples:"); sb.AppendLine(""); @@ -152,7 +153,7 @@ namespace Volo.Abp.Cli.Commands public const string Skip = "skip-db-migrations"; } - public static class StartupProject + public static class StartupProject { public const string Short = "sp"; public const string Long = "startup-project"; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs index 03e228f255..7ea20eccf4 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs @@ -34,9 +34,12 @@ namespace Volo.Abp.Cli.Commands ); } + var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long); + await ProjectNugetPackageAdder.AddAsync( GetProjectFile(commandLineArgs), - commandLineArgs.Target + commandLineArgs.Target, + version ); } @@ -55,6 +58,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine("Options:"); sb.AppendLine(""); sb.AppendLine(" -p|--project Specify the project file explicitly."); + sb.AppendLine(" -v|--version Specify the version of the package. Default is your project's ABP version or latest ABP version."); sb.AppendLine(""); sb.AppendLine("Examples:"); sb.AppendLine(""); @@ -119,6 +123,12 @@ namespace Volo.Abp.Cli.Commands public const string Short = "p"; public const string Long = "project"; } + + public static class Version + { + public const string Short = "v"; + public const string Long = "version"; + } } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs index a69957a497..5f1e18efbd 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; +using System.Xml; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Cli.Http; @@ -40,26 +41,36 @@ namespace Volo.Abp.Cli.ProjectModification Logger = NullLogger.Instance; } - public async Task AddAsync(string projectFile, string packageName) + public async Task AddAsync(string projectFile, string packageName, string version = null) { await AddAsync( projectFile, - await FindNugetPackageInfoAsync(packageName) + await FindNugetPackageInfoAsync(packageName), + version ); } - public Task AddAsync(string projectFile, NugetPackageInfo package) + public Task AddAsync(string projectFile, NugetPackageInfo package, string version = null) { - if (File.ReadAllText(projectFile).Contains($"\"{package.Name}\"")) + var projectFileContent = File.ReadAllText(projectFile); + + if (projectFileContent.Contains($"\"{package.Name}\"")) { return Task.CompletedTask; } + if (version == null) + { + version = GetAbpVersionOrNull(projectFileContent); + } + using (DirectoryHelper.ChangeCurrentDirectory(Path.GetDirectoryName(projectFile))) { Logger.LogInformation($"Installing '{package.Name}' package to the project '{Path.GetFileNameWithoutExtension(projectFile)}'..."); - CmdHelper.Run("dotnet", "add package " + package.Name); + var versionOption = version == null ? "" : $" -v {version}"; + + CmdHelper.Run("dotnet", $"add package {package.Name}{versionOption}"); var moduleFiles = ModuleClassFinder.Find(projectFile, "AbpModule"); if (moduleFiles.Count == 0) @@ -80,11 +91,22 @@ namespace Volo.Abp.Cli.ProjectModification return Task.CompletedTask; } - protected virtual async Task FindNugetPackageInfoAsync(string moduleName) + private string GetAbpVersionOrNull(string projectFileContent) + { + var doc = new XmlDocument() { PreserveWhitespace = true }; + + doc.Load(StreamHelper.GenerateStreamFromString(projectFileContent)); + + var nodes = doc.SelectNodes("/Project/ItemGroup/PackageReference[starts-with(@Include, 'Volo.')]"); + + return nodes?[0]?.Attributes?["Version"]?.Value; + } + + protected virtual async Task FindNugetPackageInfoAsync(string packageName) { using (var client = new CliHttpClient()) { - var url = $"{CliUrls.WwwAbpIo}api/app/nugetPackage/byName/?name=" + moduleName; + var url = $"{CliUrls.WwwAbpIo}api/app/nugetPackage/byName/?name=" + packageName; var response = await client.GetAsync(url); @@ -92,7 +114,7 @@ namespace Volo.Abp.Cli.ProjectModification { if (response.StatusCode == HttpStatusCode.NotFound) { - throw new CliUsageException($"'{moduleName}' nuget package could not be found!"); + throw new CliUsageException($"'{packageName}' nuget package could not be found!"); } await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); @@ -103,4 +125,4 @@ namespace Volo.Abp.Cli.ProjectModification } } } -} \ No newline at end of file +} From 873ffd49adb7b63152d6a78d6fd3a99e6832b372 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Thu, 16 Jul 2020 11:19:07 +0300 Subject: [PATCH 033/376] Cli: pre-release option for update npm command --- .../ProjectModification/NpmPackagesUpdater.cs | 34 ++++++++++++++----- .../PackagePreviewSwitcher.cs | 2 ++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs index 4730fed899..235f39a34e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs @@ -42,7 +42,7 @@ namespace Volo.Abp.Cli.ProjectModification Logger = NullLogger.Instance; } - public async Task Update(string rootDirectory, bool includePreviews = false, bool switchToStable = false) + public async Task Update(string rootDirectory, bool includePreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false) { var fileList = _packageJsonFileFinder.Find(rootDirectory); @@ -57,7 +57,7 @@ namespace Volo.Abp.Cli.ProjectModification async Task UpdateAsync(string file) { - var updated = await UpdatePackagesInFile(file, includePreviews, switchToStable); + var updated = await UpdatePackagesInFile(file, includePreviews,includeReleaseCandidates, switchToStable); packagesUpdated.TryAdd(file, updated); } @@ -176,7 +176,10 @@ namespace Volo.Abp.Cli.ProjectModification return File.Exists(Path.Combine(fileDirectory, "angular.json")); } - protected virtual async Task UpdatePackagesInFile(string filePath, bool includePreviews = false, + protected virtual async Task UpdatePackagesInFile( + string filePath, + bool includePreviews = false, + bool includeReleaseCandidates = false, bool switchToStable = false) { var packagesUpdated = false; @@ -191,7 +194,7 @@ namespace Volo.Abp.Cli.ProjectModification foreach (var abpPackage in abpPackages) { - var updated = await TryUpdatingPackage(filePath, abpPackage, includePreviews, switchToStable); + var updated = await TryUpdatingPackage(filePath, abpPackage, includePreviews, includeReleaseCandidates, switchToStable); if (updated) { @@ -210,18 +213,26 @@ namespace Volo.Abp.Cli.ProjectModification string filePath, JProperty package, bool includePreviews = false, + bool includeReleaseCandidates = false, bool switchToStable = false) { var currentVersion = (string) package.Value; var version = ""; - if (includePreviews || (!switchToStable && currentVersion.Contains("-preview"))) + if ((includePreviews || (!switchToStable && currentVersion.Contains("-preview"))) && !includeReleaseCandidates) { version = "preview"; } else { - version = await GetLatestVersion(package); + if (!switchToStable && currentVersion.Split("-").Length > 1) + { + version = await GetLatestVersion(package, true); + } + else + { + version = await GetLatestVersion(package, includeReleaseCandidates); + } } if (version == currentVersion) @@ -237,14 +248,21 @@ namespace Volo.Abp.Cli.ProjectModification } protected virtual async Task GetLatestVersion( - JProperty package) + JProperty package, + bool includeReleaseCandidates = false) { if (_fileVersionStorage.ContainsKey(package.Name)) { return _fileVersionStorage[package.Name]; } - var newVersion = CmdHelper.RunCmdAndGetOutput($"npm show {package.Name} version"); + var versionListAsJson = CmdHelper.RunCmdAndGetOutput($"npm show {package.Name} versions"); + var versionList = JsonConvert.DeserializeObject(versionListAsJson); + + var newVersion = includeReleaseCandidates + ? versionList.Last() + : versionList.LastOrDefault(v => v.Split("-").Length < 2); + var newVersionWithPrefix = $"~{newVersion}"; _fileVersionStorage[package.Name] = newVersionWithPrefix; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs index cccd468a25..f80f9a3c0d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs @@ -38,6 +38,7 @@ namespace Volo.Abp.Cli.ProjectModification await _npmPackagesUpdater.Update( solutionFolder, + false, true); } @@ -72,6 +73,7 @@ namespace Volo.Abp.Cli.ProjectModification await _npmPackagesUpdater.Update( solutionFolder, false, + false, true); } From 2c9f32b3bb88c07bd58fb8000da576cc163a43ea Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Thu, 16 Jul 2020 12:18:13 +0300 Subject: [PATCH 034/376] cli: remove abp nightly source when switched to stable --- .../PackagePreviewSwitcher.cs | 11 ++-- ...SourceAdder.cs => PackageSourceManager.cs} | 56 +++++++++++++++++-- 2 files changed, 56 insertions(+), 11 deletions(-) rename framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/{PackageSourceAdder.cs => PackageSourceManager.cs} (55%) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs index f80f9a3c0d..ee76496e32 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackagePreviewSwitcher.cs @@ -11,17 +11,17 @@ namespace Volo.Abp.Cli.ProjectModification { public class PackagePreviewSwitcher : ITransientDependency { - private readonly PackageSourceAdder _packageSourceAdder; + private readonly PackageSourceManager _packageSourceManager; private readonly NpmPackagesUpdater _npmPackagesUpdater; private readonly VoloNugetPackagesVersionUpdater _nugetPackagesVersionUpdater; public ILogger Logger { get; set; } - public PackagePreviewSwitcher(PackageSourceAdder packageSourceAdder, + public PackagePreviewSwitcher(PackageSourceManager packageSourceManager, NpmPackagesUpdater npmPackagesUpdater, VoloNugetPackagesVersionUpdater nugetPackagesVersionUpdater) { - _packageSourceAdder = packageSourceAdder; + _packageSourceManager = packageSourceManager; _npmPackagesUpdater = npmPackagesUpdater; _nugetPackagesVersionUpdater = nugetPackagesVersionUpdater; Logger = NullLogger.Instance; @@ -44,8 +44,7 @@ namespace Volo.Abp.Cli.ProjectModification public async Task SwitchToNightlyPreview(CommandLineArgs commandLineArgs) { - // TODO: Remove this when switched to stable - _packageSourceAdder.Add("ABP Nightly", "https://www.myget.org/F/abp-nightly/api/v3/index.json"); + _packageSourceManager.Add("ABP Nightly", "https://www.myget.org/F/abp-nightly/api/v3/index.json"); var solutionPath = GetSolutionPath(commandLineArgs); var solutionFolder = GetSolutionFolder(commandLineArgs); @@ -61,6 +60,8 @@ namespace Volo.Abp.Cli.ProjectModification public async Task SwitchToStable(CommandLineArgs commandLineArgs) { + _packageSourceManager.Remove("ABP Nightly"); + var solutionPath = GetSolutionPath(commandLineArgs); var solutionFolder = GetSolutionFolder(commandLineArgs); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceManager.cs similarity index 55% rename from framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceAdder.cs rename to framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceManager.cs index 3e651b3bf1..7272a41506 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceManager.cs @@ -7,19 +7,18 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Cli.ProjectModification { - public class PackageSourceAdder: ITransientDependency + public class PackageSourceManager: ITransientDependency { - public ILogger Logger { get; set; } + public ILogger Logger { get; set; } - public PackageSourceAdder() + public PackageSourceManager() { - Logger = NullLogger.Instance; + Logger = NullLogger.Instance; } public void Add(string sourceKey, string sourceValue) { - var nugetConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - "NuGet", "NuGet.Config"); + var nugetConfigPath = GetNugetConfigPath(); if (!File.Exists(nugetConfigPath)) { @@ -63,6 +62,51 @@ namespace Volo.Abp.Cli.ProjectModification } } + public void Remove(string sourceKey) + { + var nugetConfigPath = GetNugetConfigPath(); + + if (!File.Exists(nugetConfigPath)) + { + return; + } + + var fileContent = File.ReadAllText(nugetConfigPath); + + if (!fileContent.Contains($"\"{sourceKey}\"")) + { + return; + } + + Logger.LogInformation($"Removing \"{sourceKey}\" from nuget sources..."); + + try + { + var doc = new XmlDocument() { PreserveWhitespace = true }; + + doc.Load(GenerateStreamFromString(fileContent)); + + var nodes = doc.SelectNodes($"/configuration/packageSources[@key='{sourceKey}']"); + + if (nodes != null && nodes.Count > 0) + { + nodes[0].ParentNode.RemoveChild(nodes[0]); + } + + File.WriteAllText(nugetConfigPath, doc.OuterXml); + } + catch + { + Logger.LogWarning($"Removing \"{sourceKey}\" from nuget sources FAILED."); + } + } + + private static string GetNugetConfigPath() + { + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "NuGet", "NuGet.Config"); + } + private static Stream GenerateStreamFromString(string s) { var stream = new MemoryStream(); From 3747b2b57983d0a250d625981c7a594919a93b48 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Thu, 16 Jul 2020 14:36:43 +0300 Subject: [PATCH 035/376] docs module: set latest stable version as latest when there is a prerelease --- .../Pages/Documents/Project/Index.cshtml | 10 +++--- .../Pages/Documents/Project/Index.cshtml.cs | 32 ++++++++++--------- .../Pages/Documents/Search.cshtml.cs | 3 +- .../src/Volo.Docs.Web/Utils/VersionHelper.cs | 11 +++++++ 4 files changed, 35 insertions(+), 21 deletions(-) create mode 100644 modules/docs/src/Volo.Docs.Web/Utils/VersionHelper.cs diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml index 90a754b1a9..71c7d4790c 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml @@ -53,7 +53,7 @@ /// 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 33b53d012e92c2b9d55862113d08d349706c1441 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Fri, 17 Jul 2020 17:50:46 +0300 Subject: [PATCH 057/376] Github releases: ensure versions are listed by semantic compare --- .../src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs | 5 +++-- .../Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs | 3 +++ .../Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs | 2 ++ modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs index 8b58ad2d9a..1d2ddb650b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs @@ -78,11 +78,12 @@ namespace Volo.Abp.Cli.NuGet var versions = JsonSerializer .Deserialize(responseContent) .Versions - .Select(SemanticVersion.Parse); + .Select(SemanticVersion.Parse) + .OrderByDescending(v=> v, new VersionComparer()).ToList(); if (!includePreviews && !includeNightly && !includeReleaseCandidates) { - versions = versions.Where(x => !x.IsPrerelease); + versions = versions.Where(x => !x.IsPrerelease).ToList(); } var semanticVersions = versions.ToList(); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs index 235f39a34e..140d6b893c 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using NuGet.Versioning; using Volo.Abp.Cli.Http; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; @@ -259,6 +260,8 @@ namespace Volo.Abp.Cli.ProjectModification var versionListAsJson = CmdHelper.RunCmdAndGetOutput($"npm show {package.Name} versions"); var versionList = JsonConvert.DeserializeObject(versionListAsJson); + versionList = versionList.OrderByDescending(SemanticVersion.Parse, new VersionComparer()).ToArray(); + var newVersion = includeReleaseCandidates ? versionList.Last() : versionList.LastOrDefault(v => v.Split("-").Length < 2); diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index e7bc6154fa..a6670f8d72 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -17,6 +17,7 @@ using Volo.Docs.HtmlConverting; using Volo.Docs.Models; using Volo.Docs.Projects; using Volo.Docs.Utils; +using NuGet.Versioning; namespace Volo.Docs.Pages.Documents.Project { @@ -252,6 +253,7 @@ namespace Volo.Docs.Pages.Documents.Project var output = await _projectAppService.GetVersionsAsync(Project.ShortName); var versions = output.Items + .OrderByDescending(i => SemanticVersion.Parse(i.Name), new VersionComparer()) .Select(v => new VersionInfoViewModel(v.DisplayName, v.Name)) .ToList(); diff --git a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj index a82e806e24..aef4937c88 100644 --- a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj +++ b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj @@ -25,6 +25,7 @@ + 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 058/376] 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 059/376] 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(); From 2bc29b2a19165112d55c3f994b1b2bab83201dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 17 Jul 2020 19:06:17 +0300 Subject: [PATCH 060/376] re-init widget on refresh & replace --- .../jquery/widget-manager.js | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 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 e0fdf0bafa..1dd7717070 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 @@ -25,11 +25,16 @@ opts.filterForm = $(opts.filterForm); } - var getFilters = function ($widgetWrapperDiv) { + var publicApi = { + init: init, + refresh: refresh + }; + + function getFilters($widget) { var filters = {}; if (opts.filterForm) { - opts.filterForm.each(function() { + opts.filterForm.each(function () { filters = $.extend(filters, opts.filterForm.serializeFormToObject()); }); } @@ -38,55 +43,66 @@ filters = $.extend(filters, opts.filterCallback()); } - var widgetApi = $widgetWrapperDiv.data('abp-widget-api'); + var widgetApi = $widget.data('abp-widget-api'); if (widgetApi && widgetApi.getFilters) { filters = $.extend(filters, widgetApi.getFilters()); } return filters; - }; + } - var init = function () { - opts.wrapper.findWithSelf('.abp-widget-wrapper').each(function () { - var $widgetWrapperDiv = $(this); - var widgetName = $widgetWrapperDiv.attr('data-widget-name'); + function init($widgets) { + if(!$widgets){ + $widgets = opts.wrapper.findWithSelf('.abp-widget-wrapper'); + } + + $widgets.each(function () { + var $widget = $(this); + $widget.data('abp-widget-manager', publicApi); + var widgetName = $widget.attr('data-widget-name'); var widgetApiClass = abp.widgets[widgetName]; if (widgetApiClass) { - var widgetApi = new widgetApiClass($widgetWrapperDiv); - $widgetWrapperDiv.data('abp-widget-api', widgetApi); + var widgetApi = new widgetApiClass($widget); + $widget.data('abp-widget-api', widgetApi); if (widgetApi.init) { - widgetApi.init(getFilters($widgetWrapperDiv)); + widgetApi.init(getFilters($widget)); } } }); - }; + } + + function refresh($widgets) { + if(!$widgets){ + $widgets = opts.wrapper.findWithSelf('.abp-widget-wrapper'); + } - var refresh = function () { - opts.wrapper.findWithSelf('.abp-widget-wrapper').each(function () { - var $widgetWrapperDiv = $(this); + $widgets.each(function () { + var $widget = $(this); - var refreshUrl = $widgetWrapperDiv.attr('data-refresh-url'); + var refreshUrl = $widget.attr('data-refresh-url'); if (refreshUrl) { abp.ajax({ url: refreshUrl, type: 'GET', dataType: 'html', contentType: 'application/x-www-form-urlencoded; charset=UTF-8', - data: getFilters($widgetWrapperDiv) + data: getFilters($widget) }).then(function (result) { - $widgetWrapperDiv.replaceWith($(result)); + var $result = $(result); + $widget.replaceWith($result); + init($result); }); } else { - var widgetApi = $widgetWrapperDiv.data('abp-widget-api'); + var widgetApi = $widget.data('abp-widget-api'); if (widgetApi && widgetApi.refresh) { - widgetApi.refresh(getFilters($widgetWrapperDiv)); + widgetApi.refresh(getFilters($widget)); } } }); - }; + } if (opts.filterForm) { - opts.filterForm.each(function() { + opts.filterForm.each(function () { $(this).submit(function (e) { e.preventDefault(); refresh(); @@ -94,11 +110,6 @@ }); } - var publicApi = { - init: init, - refresh: refresh - }; - opts.wrapper.data('abp-widget-manager', publicApi); return publicApi; From 263ee2d21a6685d50d1e705c40415b2a6a1d1d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 17 Jul 2020 19:06:43 +0300 Subject: [PATCH 061/376] Implemented refresh on reaction widget. --- .../Controllers/CmsKitControllerBase.cs} | 6 ++--- .../Volo/CmsKit/CmsKitPublicControllerBase.cs | 8 ++++++ .../Reactions/ReactionPublicController.cs | 2 +- .../CmsKitPublicWidgetsController.cs | 15 +++++++++++ .../ReactionSelectionViewComponent.cs | 3 ++- .../Components/ReactionSelection/default.js | 27 +++++++++---------- 6 files changed, 42 insertions(+), 19 deletions(-) rename modules/cms-kit/src/{Volo.CmsKit.Public.HttpApi/Volo/CmsKit/CmsKitPublicController.cs => Volo.CmsKit.Common.HttpApi/Volo/CmsKit/Controllers/CmsKitControllerBase.cs} (55%) create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/CmsKitPublicControllerBase.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/CmsKitPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Common.HttpApi/Volo/CmsKit/Controllers/CmsKitControllerBase.cs similarity index 55% rename from modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/CmsKitPublicController.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.HttpApi/Volo/CmsKit/Controllers/CmsKitControllerBase.cs index 75f38932f1..8938109b3b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/CmsKitPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.HttpApi/Volo/CmsKit/Controllers/CmsKitControllerBase.cs @@ -1,11 +1,11 @@ using Volo.Abp.AspNetCore.Mvc; using Volo.CmsKit.Localization; -namespace Volo.CmsKit +namespace Volo.CmsKit.Controllers { - public abstract class CmsKitPublicController : AbpController + public class CmsKitControllerBase : AbpController { - protected CmsKitPublicController() + public CmsKitControllerBase() { LocalizationResource = typeof(CmsKitResource); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/CmsKitPublicControllerBase.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/CmsKitPublicControllerBase.cs new file mode 100644 index 0000000000..86c9f90eb3 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/CmsKitPublicControllerBase.cs @@ -0,0 +1,8 @@ +using Volo.CmsKit.Controllers; + +namespace Volo.CmsKit +{ + public abstract class CmsKitPublicControllerBase : CmsKitControllerBase + { + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Reactions/ReactionPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Reactions/ReactionPublicController.cs index 4deb3796a3..2fead1398f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Reactions/ReactionPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Reactions/ReactionPublicController.cs @@ -8,7 +8,7 @@ namespace Volo.CmsKit.Reactions [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area("cms-kit")] [Route("api/cms-kit-public/reactions")] - public class ReactionPublicController : CmsKitPublicController, IReactionPublicAppService + public class ReactionPublicController : CmsKitPublicControllerBase, IReactionPublicAppService { protected IReactionPublicAppService ReactionPublicAppService { get; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs new file mode 100644 index 0000000000..83923eaf17 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.CmsKit.Web.Controllers +{ + //TODO: Consider to move to an area, but also consider to not have the same prefix with API Controllers which can be problem in case of a tiered architecture + public class CmsKitPublicWidgetsController : CmsKitPublicControllerBase + { + public async Task ReactionSelection(string entityType, string entityId) + { + //TODO: Can we change "CmsReactionSelection" to typeof(ReactionSelectionViewComponent) + return ViewComponent("CmsReactionSelection", new {entityType, entityId}); + } + } +} 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 efb4db779e..882baf51ed 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 @@ -11,7 +11,8 @@ namespace Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection [ViewComponent(Name = "CmsReactionSelection")] [Widget( ScriptTypes = new[] {typeof(ReactionSelectionScriptBundleContributor)}, - StyleTypes = new[] {typeof(ReactionSelectionStyleBundleContributor)} + StyleTypes = new[] {typeof(ReactionSelectionStyleBundleContributor)}, + RefreshUrl = "/CmsKitPublicWidgets/ReactionSelection" )] public class ReactionSelectionViewComponent : AbpViewComponent { 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 c7b31b1e1b..1e7f7a85d9 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 @@ -2,27 +2,27 @@ $(document).ready(function () { abp.widgets.CmsReactionSelection = function ($widget) { + var $reactionSelection = $widget.find('.cms-reaction-selection'); + var widgetManager = $widget.data('abp-widget-manager'); function getFilters() { - return {}; - } - - function refresh(filters) { - location.reload(); //TODO: JUST TESTING !!!!!!!! + return { + entityType: $reactionSelection.attr('data-entity-type'), + entityId: $reactionSelection.attr('data-entity-id') + }; } function init(filters) { - var $wrapper = $widget.find('.cms-reaction-selection'); $widget.find('.cms-reaction-icon').each(function () { var $icon = $(this); $icon.click(function () { var methodName = $icon.hasClass('cms-reaction-icon-selected') ? 'delete' : 'create'; - volo.cmsKit.reactions.reactionPublic[methodName]({ - entityType: $wrapper.attr('data-entity-type'), - entityId: $wrapper.attr('data-entity-id'), - reactionName: $icon.attr('data-name') - }).then(function () { - refresh(); + volo.cmsKit.reactions.reactionPublic[methodName]( + $.extend(getFilters(), { + reactionName: $icon.attr('data-name') + }) + ).then(function () { + widgetManager.refresh($widget); }); }); }); @@ -30,8 +30,7 @@ return { init: init, - refresh: refresh, - getFilters : getFilters + getFilters: getFilters }; }; From 298574066c0875c2f46bd30f0c3e912f060c2a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 17 Jul 2020 19:08:15 +0300 Subject: [PATCH 062/376] Update CmsKitPublicWidgetsController.cs --- .../Controllers/CmsKitPublicWidgetsController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs index 83923eaf17..3534811ad3 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection; namespace Volo.CmsKit.Web.Controllers { @@ -8,8 +9,7 @@ namespace Volo.CmsKit.Web.Controllers { public async Task ReactionSelection(string entityType, string entityId) { - //TODO: Can we change "CmsReactionSelection" to typeof(ReactionSelectionViewComponent) - return ViewComponent("CmsReactionSelection", new {entityType, entityId}); + return ViewComponent(typeof(ReactionSelectionViewComponent), new {entityType, entityId}); } } } From b3fae140c7feca266aca47d753835f791b4eb89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 17 Jul 2020 21:18:16 +0300 Subject: [PATCH 063/376] Update default.js --- .../Pages/CmsKit/Shared/Components/ReactionSelection/default.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1e7f7a85d9..933d127e91 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 @@ -12,7 +12,7 @@ }; } - function init(filters) { + function init() { $widget.find('.cms-reaction-icon').each(function () { var $icon = $(this); $icon.click(function () { From 0bce76cc341020c4c1004ef20b345af35844b539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 17 Jul 2020 22:13:25 +0300 Subject: [PATCH 064/376] Show popover to react. --- .../CmsKit/Localization/Resources/en.json | 2 +- .../CmsKit/Localization/Resources/tr.json | 1 + .../ReactionSelection/Default.cshtml | 26 ++++------ .../Components/ReactionSelection/default.css | 9 +++- .../Components/ReactionSelection/default.js | 50 +++++++++++++++---- 5 files changed, 59 insertions(+), 29 deletions(-) diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json index 2dd71201b7..e1bdb1b209 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json @@ -1,6 +1,6 @@ { "culture": "en", "texts": { - + "PickYourReaction": "Pick your reaction" } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json index d7fb14a7c7..ce0d27fd3c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json @@ -1,5 +1,6 @@ { "culture": "tr", "texts": { + "PickYourReaction": "Tepkinizi seçin" } } 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 3927ac3fdb..4a4ee6cfb5 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,22 +1,18 @@ @model Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection.ReactionSelectionViewModel - -
- Pick a reaction: + + + -
- Current reactions: - @foreach (var reaction in Model.Reactions.Where(r => r.Count > 0)) - { - - - @reaction.Count + + }
+ @foreach (var reaction in Model.Reactions.Where(r => r.Count > 0)) + { + + @(reaction.Count) + + }
diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css index 844fefaafa..e984fa3d77 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css @@ -1,8 +1,13 @@ -.cms-reaction-icon +.cms-reaction-select-icon { cursor: pointer; } +.cms-reaction-icon +{ + cursor: pointer; + padding: 2px; +} .cms-reaction-icon-selected { - border: 1px solid gray; + background-color: #eee; } 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 933d127e91..62a060a543 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,30 @@ (function ($) { + + var l = abp.localization.getResource('CmsKit'); + + var myDefaultWhiteList = $.fn.tooltip.Constructor.Default.whiteList; + + if (myDefaultWhiteList.img.indexOf('data-name') < 0) { + myDefaultWhiteList['img'].push('data-name'); + } + $(document).ready(function () { abp.widgets.CmsReactionSelection = function ($widget) { - var $reactionSelection = $widget.find('.cms-reaction-selection'); var widgetManager = $widget.data('abp-widget-manager'); + var $reactionArea = $widget.find('.cms-reaction-area'); + var $selectIcon = $widget.find('.cms-reaction-select-icon'); + var $popoverContent = $widget.find('.cms-reaction-selection-popover-content'); function getFilters() { return { - entityType: $reactionSelection.attr('data-entity-type'), - entityId: $reactionSelection.attr('data-entity-id') + entityType: $reactionArea.attr('data-entity-type'), + entityId: $reactionArea.attr('data-entity-id') }; } - function init() { - $widget.find('.cms-reaction-icon').each(function () { + function registerClickOfReactionIcons($container) { + $container.find('.cms-reaction-icon').each(function () { var $icon = $(this); $icon.click(function () { var methodName = $icon.hasClass('cms-reaction-icon-selected') ? 'delete' : 'create'; @@ -22,24 +33,41 @@ reactionName: $icon.attr('data-name') }) ).then(function () { + $selectIcon.popover('hide'); widgetManager.refresh($widget); }); }); }); } + function init() { + + $selectIcon.popover({ + placement: 'right', + html: true, + title: l('PickYourReaction'), + content: $popoverContent.html() + }).on('shown.bs.popover', function () { + var $popover = $('#' + $selectIcon.attr('aria-describedby')); + registerClickOfReactionIcons($popover); + }); + + registerClickOfReactionIcons($widget); + } + return { init: init, getFilters: getFilters }; }; - $('.abp-widget-wrapper[data-widget-name="CmsReactionSelection"]').each(function () { - var widgetManager = new abp.WidgetManager({ - wrapper: $(this), - }); + $('.abp-widget-wrapper[data-widget-name="CmsReactionSelection"]') + .each(function () { + var widgetManager = new abp.WidgetManager({ + wrapper: $(this), + }); - widgetManager.init(); - }); + widgetManager.init(); + }); }); })(jQuery); From c31ecc36d8b6b09d8548e2eddaf898c400824122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 17 Jul 2020 23:03:16 +0300 Subject: [PATCH 065/376] Add more reaction icons --- .../CmsKitCommonWebModule.cs | 6 ++++++ .../wwwroot/cms-kit/icons/confused.png | Bin 0 -> 2338 bytes .../wwwroot/cms-kit/icons/eyes.png | Bin 0 -> 1326 bytes .../wwwroot/cms-kit/icons/heart.png | Bin 0 -> 2694 bytes .../wwwroot/cms-kit/icons/hooray.png | Bin 0 -> 3258 bytes .../wwwroot/cms-kit/icons/rocket.png | Bin 0 -> 2984 bytes .../wwwroot/cms-kit/icons/thumbsdown.png | Bin 0 -> 2890 bytes .../Volo/CmsKit/Reactions/StandardReactions.cs | 10 ++++++++-- .../Volo/CmsKit/CmsKitDomainModule.cs | 6 ++++++ .../Components/ReactionSelection/Default.cshtml | 11 ++++++----- .../Components/ReactionSelection/default.css | 4 ++-- .../Components/ReactionSelection/default.js | 7 ++++--- 12 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/confused.png create mode 100644 modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/eyes.png create mode 100644 modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/heart.png create mode 100644 modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/hooray.png create mode 100644 modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/rocket.png create mode 100644 modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/thumbsdown.png diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/CmsKitCommonWebModule.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/CmsKitCommonWebModule.cs index dd991aa114..54743b948f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.Web/CmsKitCommonWebModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/CmsKitCommonWebModule.cs @@ -20,6 +20,12 @@ namespace Volo.CmsKit.Web { options.ReactionIcons[StandardReactions.Smile] = new LocalizableIconDictionary("/cms-kit/icons/smile.png"); options.ReactionIcons[StandardReactions.ThumbsUp] = new LocalizableIconDictionary("/cms-kit/icons/thumbsup.png"); + options.ReactionIcons[StandardReactions.Confused] = new LocalizableIconDictionary("/cms-kit/icons/confused.png"); + options.ReactionIcons[StandardReactions.Eyes] = new LocalizableIconDictionary("/cms-kit/icons/eyes.png"); + options.ReactionIcons[StandardReactions.Heart] = new LocalizableIconDictionary("/cms-kit/icons/heart.png"); + options.ReactionIcons[StandardReactions.Hooray] = new LocalizableIconDictionary("/cms-kit/icons/hooray.png"); + options.ReactionIcons[StandardReactions.Rocket] = new LocalizableIconDictionary("/cms-kit/icons/rocket.png"); + options.ReactionIcons[StandardReactions.ThumbsDown] = new LocalizableIconDictionary("/cms-kit/icons/thumbsdown.png"); }); Configure(options => diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/confused.png b/modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/confused.png new file mode 100644 index 0000000000000000000000000000000000000000..4ecf0c98c1dfbe8c450d5d8666d3602820af25d1 GIT binary patch literal 2338 zcmV+-3ElRIP)vUJ%hGP;vhOwLvNsT05yueqh$e)MV98~T`1dlR3ZE@$ z&SQVF z-C+#$4htG1yLmlR3>)Is^=u(3_I`gwTT1T-=b>ays{7Ndh~U1UhW3MVz`iA+zcISe z!^#orAtR1+G#QCk2&F6=$91>A_XR;ZCUBouL)$;5gT)vp4BUDV;doDOZfXFzlQJ;D&5Q_ze#@y|^x0Xy3!M%}S9 ziIm|=dFr&#S}{$G4u|cp_tI}M19@9Z+5P>e#yWV7jgJZWTW_;j*ugn5>YX3X?^DEe zM(!7|2sSe}K+NGhI`6hOOaptpJ>3c;r6IoP?6SM4?ss% zDtNExV@_Vcbyf-1!U;XAMIJjDwYYHI$Yx-pR}mD6{YW{sPq`iaw@n7`B^`Y~B=F#J zYBR+PeNIzO5)pZvPZKF~vmVG2i=`Jj;4f6k?mV1g?zv3v>cz~fzd-*>cB?+FKlw}W(Ayw z=ML4Jra&5KbrIR--Mwh$7rG=8zdcOtFq*snAwAo$?O;mzH4P zHA7f&#Afb|2YKv;u*kP;VpBzyhZ!9;G@?QANo0$Z$b~)nE$<{!1ET`=()&b`^qada zdvW;Se-N~79W@5%Iwcb;LR~nKpVrZcIy`$I1IkT0_^?tB?uH1myK7l+tU}M*sy-M& zR@syV)}o2r2siWDqb!*8R&k*Hz#K^(wbo_A%4bv{lgaw9e2D^@P7XXrxOTz-%N8r| zXzTeOtHF6$a$X_Q@^mXr?ud&U3?1t}RAhjyfg-PS)#(u206RLbF2wL#J}5IKcCo2B}1cXQdZ z^keJJsgew^uPnIIgmtUK&*|6vUK6sdBRi$V1IN348@C?@GQeAW{vS-1)cCH=p$+i* zOW_+})vrPuU{A5M9VgWmi6h3kHG$@TC4x2`QW~d-A5v-4+uE?(%70TEvaK_FC3yg4 zkir1vfmVPE_#*`iX?gpVOn5j;9#CPqTn6>W!=JY`M>2wvU-XEaf~2%SSgjIM;9SrZ zzyWI!(r>;z@W}ng7c~J5`Ch4H{is$TJfJa<0c?nfE4c^W(Zf?;Q}Ss2 z#FrId&enpjNkVm}Arm&O)xuXEQ}DLFwOlEJpJY%CK^(9IGJqQ)c7LN2jhSK!xW)_+ zbPCjGP|`3e;ky!Q3Wy+Bt0PN|N_a17Lk7X~q6jit4d6bj6x-sneg+T+ot?+=#HS&1 zG=h%jMGSb?-vD`REl-8_&xY=+hEa+3y|aY@-UxKu{S#ga+mQsm%Z8Yt>!Jaww(DRm zZg_sMLIsN+zMVZP6*72ykpfmet%8Er7eL+n`e^n|Wj>Ia#;MR99Aq-a4dUV4qwWYbMot7Qc2Rsxi3W|Ko{8E z1RweXubY_@z--IeG+_bbdhZM;|uRy~6!}5zcLp zM9P)vg^oR`;69=m5L|~fkd+>o^izxFVEmm5YPPEB*+D_a-{6ap8LW9u4*%Om-wh2Me@hbNPeC~w#|9$ST($^b^wA}Q_OfK?ESHTaw3YUy zy7p}RK?1awrVeSavlhe) z;y%Qm`Nhas3!Sb~wkW)z#gqijt!aZt9F5+xDUtUrikyh0Y!F4
M}Q=1Sznb=!-k zV0@StyC7Gb4EDmwf;hp2$mR2Ws02MB1C`i=00HZUc=U<~Fe*oG3<|i8qN#it?$?Kx zmbe=m*nBoz#Fo#r=!QmA&W->9N=PVHI80M1a8k5JQYjcaQlMk&d;)!@@Az-6<{31l z@SREIRd8op>^hz8V_zw3Sc=$3y2bWnv_ns39?ipotMR21GP5 zK@lNlwCB4Utn0pDA8Z0!*LMBx))riT=Da;Ur`via^K`rF|4Gi>@1OU1zs~c#t5!AC zP(uwhfw5_mi&(^xv&_2S{US+X2yzX^1>)Zf*2vBd}mX=SX=r}IuXkv&kO~M zl&mNUqnxmrVjKXOxhp?W57x=yc#x>bpq52B zOdB(kBoTD9&+EZf_V5}b(nm^6V4Gzr3}6Rh#dIt#E}=cbs#8J7$yQD9o+ zF^Yz~%`5BNVLx_|6jNAal6KA$axp83sZ0~YKtJV`wPlRV%6)iXOD?3cJ&0H{Ubs z44|i%-Z=v>V=FB@&pwX1nuO7Mys*vyI>U_N->yc&4MbS8)Utxv83ceTi&!Q5_o~MULM%$bNRSi&olrpM=Zr#9YNbw1`*M zsR%DzB}s-ny?n|cd>r8{GcJGhtSBx!Q2+4CIs-VMaa-hJ)-`u(;*~>G&fz91`XR5Z zQ1|3iT8pgc^5R@W#%QhwTV0y#=7}yhmpRef6-0|wq+oY=Wec;lP^5aX&PIGz zneDgwTc^dG7I@BXFXKe%L!MPP)r+mpXaUDe=IN6fYeyCPh6f4K94`@xoSjNKZ*ggWF7shZfVS9OXxr2)EFYr?idr zW~-0mCMjv&?&UYGs1@dG*960;1QPAfEC*Zt+VON?NFv1FOxQ8b7+nOAuIo=O7h9!2 z@ADt`7Xt(d(@#HP3%Us5PClCsJBsZ-DJ5TLv+aHr3 kZC|_6Y(ot-)X)m*Ur^}){MmW^;s5{u07*qoM6N<$f?P;@e*gdg literal 0 HcmV?d00001 diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/heart.png b/modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/heart.png new file mode 100644 index 0000000000000000000000000000000000000000..578091d6d2e0c42df96ae14bf053bbaba390e06d GIT binary patch literal 2694 zcmV;13VHR3P)ix7y#hKYTT++)VcRo-)?Yscj$0yaHpkj=!c4mCNAfGarfk8sBqWie;4=U2D;ms zFFD;`=TP=!PxfTbOizgO<$lR_1|_`~Q2bFy@w>s*;;c_`;asOnmAGWM3VT)}ISk@wdW@_3Wtdd5Khq0$#$y99q01L%-U z$3X%f$3YKhgXgu9YiNL-*q@*h1yxe!0F;U9HEUKu;T7q|!o78%tv^;ABtWmlbUXa7 zhyOuAwUbj_!P%DzMxHs>ITipknMvLR)I3_o@SAc@bQH96tb0LR5S@gesR<-N<4_~s zMwB=J&`g9RKjl;6BQz22Vmb*Xj3-DsuO5bVD>Ze9VqMCJE~Dg?i#Rp|G?5A4D53aK z5y8LRa9JZZbSE)%7hG-!iF0BHwS!Np2Sn0qDt<+zxCqd6_$+$EulVn%;`W3mjgb_v z4gC%1W~T0h96KP_2H=F;iz)t5M$Gd7jc42!3mlFcMcDk~#injD9l8xW>`U#-A;_>T z5OxxiOMuG$Cd5`-`v96uIFFsMi?5P=vZ;@nK1mOztH1bm7+5Rh-Du`&7cq4qHhz~F zxu*ddZOjV=l&&qn#t)}y=td(~x4(17+)TL4Yy--78iA=39_^(m|v0cc!nrR7)R za}kD9(cuoh@QGvwd!w_USJ|-`0BlU`tB^ zjEw?f{tyKB?rll`ID`$$Nt~TbW4s7WaH}AHD+mtENtl4_UOe*3r`{JBo0G466Tk=srl+OlH6<(< zf$)VW@s4t9>ob8NMnNf!zg|N2XTpGsxrv)=TLGMHY(m4+VFj(gj8DA$g#`{p zUYdAsXi)NaeNX1q_iYkiTl$MgBojIZO_QL=Dv0Bc0Yi)eJTcOXKA8!cxtN=UM#|TerEFj}!FMYv(Q3+QsSm*uU zh(t@cRr0p@bM?jBrB5wPEVLD}-UtRn(JU|o50wGf5kARq9xqPx~9E)-V*QhJ&<@NcCt{&`k@gC|9edZ@ceIw zGsD$IT&z~eVFI$CYH*AoG{Q1N{1GBYUi1R+d{qo#EYWVpRq_(AvwltSvsLj->;$w8 zAhAgH|A8Tf4?lhU?D_kXSiBD?Fe!(N2n#P-&WWZIn0cwGphwvm9(S)fwCM?!5;k09fT0>^2GHjOc zj%@|PYyPhFD)qI5YuY!+yu_0}XlzFd07Hxdw8Fpos|FC3i*3TJWrB`KwS>nAkZMrM z3>mU&3g5b(?Zs9*XfRf)K_;jg z{6@HDs5*#@kx+@1V8R}^Gj8{~Q}Xt-_lp-L4#6-S1cn#|T~YK)poOjpIvsRGy4Bz{ zLS~TDHZ;XSVkNjnG)Wxc%6g=%Hx@q%I-s#Dj=v5J;X{Qm{4@vQh-c#jkO@{bc#KeM z*k)LUc#Ltx`bCqtMz~w@74cQ!6Vl*t6o042&LDU{FvKV*20_Xv4?v)2vwtp-&@qBk zjgT2+#WqExiYZh?j%b3{lxUxDE9*?wcpZi-C&2BUg~H>2Aw~hglb3ol2Z*BkRf8(!;+9-iFUH>7w*rxxBugK0vMs7LKJ@J-QkcqP_-K;$*Tt_rs@Z03D9Yi2drEYTYfZlC|m z{&hWVZI1*-C=jfKZk`5XjZ4bg8m<|(A!62#o|j<1=yeJw#{nxF75)=oY!nC%!{=l1 z9fO`K$ZrNIIEKg+((J=p2dw>kz5Js6+2>8SuTXdjFg6NoXhb{Ek+^9lJf`@VAe$HL z>wTX6-v!1+K@H{SJm>Ma8D66kVZSm4%2CAZ|8w*uFL@9!E`0D(jN>oRxr4eF>_hnO zmKus-_#t3?@WD%F%-zujeGR@MF!fO2g+qhyoy#y`Y(JHLp`c68zjW-? zLqT1-g5V=8qk(-i5BeaU_nA_XyaAZCP_QOEKWW0DeJ~G(D}B$>{|YdTP_QPP2XOQl z;_T=io(G2^o_!BWz~n(eLof#(gQM}!UAiCay`jgflcirg<}nWdCJzeoKqH#)ANXI9 zC&L~R&x9~BDE+@-@I4WjyeP;`SCYK6BaUw<(S$uBzE}}|6)H3aW<4la7o{M0C-2r} zy=mGl@c`9G@z)j8^p(J@7X|BuGvV#1gq!idGGWKhdM1F?sN-%UDA*9Hgq|HXVHA`r znZL0+irxgwMp3X~WJ322nJ@xMRq=l)6y5^NW>Byx(1#y{3AeH&N4I(4Nql=#(_4Yr zEDAP@Ot^WwPKV>wY0r5CrJRzR-#}_=}FUPAzOd!*yJ0i1J%1d3_aTu1WyKLt5LA! z@Y@&O%k{&H^@`_*vh5Y|qquiG6qxNm!FIsU6Yk%cBt;78hoG^X7aYEy=bo-G{4IaI z0?c-yV7sXN_#zCy3PHD*^-i+EG1q~$+yl&ZqhPzyCrdYSI3AG+o?*vh4ko+@n4Lhu zj!;h1mq6g(JM=BI^XVNM3lG;3?Wv!?J=#^G%R&STRV<0GpMz7YO~$eG0ki>YA9lby4oO?G2 zc##mmnSM|Z5R_UbBY+UxaViOh*n2m09TU=tfX0Az%!mO`z^IgRKLqnrJ18d3(fj6i zO|>CfCVD`C1XWltn#k7A1J@fpgY~ApAzIUSR35n6Rg8|22Wy!LL@oUs^!@Ij3Hu1G z4h=vpd(Phb1W=HUE+S-5gJmG_LNwqk-J!g-rd`e^0G^k6fGYexm@iX+DzMvsJ2bh{ zALG*E-c3#>H4{*5Z}&s=^lJ3$tIm)%EC>yO*svs=^K-Q3jy1#v1yJ1>fm%j^@rY@U zHMF|t3rV7e;KY}?1zZJ+a_RaG$>%uH$LwT!Ca-sH7jX}0WO+DOD;n_30RetVRRUax z0S!9Y!QSnLTJ{fH3kcL3C*cI;Tn4BQ(KBOvG0$9_(s=3L23euKO>^b;QH3DtnfPaqj z#lV~ZFX}grU_JfZf5DTCgz?Ci>Z^g1WTUmAk8SWzs~Fy6@UgNW1l@qrH{p)YcEY;$ z;hE!tG_`7!a}o39R)gSQrg}Lr*yXajK0m@KRpC7;v?NGh7C`mo2wZEtCrD@7)@$$! z!@Uvw_bm8ZsSvPZC%R$*FPj)$;CWZmSz<}4M=AjevcgwjB*G2Foc zOF(v+NS#wcJQ~dckCi=-&mUkx*uBn+RTo9Lu5)P6#mdc2CO<^KKbo5i`4w*a!IEQiObu5l9+Nt^$S^r!r zh56D*_ORu|ftxY+j&y$Q9C)TVC9tK^4`Tc&L&X^}u&V+<{a)^(a4f4hB!PvLHfhBWiHYP;RGW=t&F9X|?1TdE3 zU*Mr$hbyYbNI6Zq*&`S0`il_?^&Xh!-^OMM8Beg$TjEK1x!!e0g2IaSfWIm zheRk9+Nh`~H!k2UL@VgcyaY4?EF?=B;RZY6@99k&IZSe6TM3t|a)3tNsvpqn5G@>>Zi#cL!Jki!pYx7i9@ zL0USYYmb4XF-&WpV*1Lb?(}H*P^>G>34%D>;bqYTsC^?UiRaX?Y~IZM>=9TMI>{;l zT6!rb->c~7yRp7lg}a%`Mg7)L9sRpIPC)HZ$>oXzBO&$W$pjb&)Uhq)V#7|=V?Wnu zBK~Ck;=~k-K%1>qZ^ZxaIQW)g;pFlI{!m}!1D|Y=0T&3nO9Cne2~*C1Ju#0mNS^tI znBQ;AAS&R%x1a*H_KQoG`eQy>%zl4pJ~bR#PIY1RBE z{T+3mi2qalVL%DxR&z*FQ+db_;Pf!oKFtVYRj|C9DtK2l4VpFKkcLkZL*kT*b1PnW zdSLVbnu~@nB)i{mT+~58+b14uEQlj1(E$nQ`*1^ZFVt%y;O}gPATfayQHrk?O~4ak ze;*B*UPfk@AG8#E5%3+x6!^kY)eK1JrjbFBdXlZ|(6%(@ zsaN{1{C9X{o07%Qn1+B2LjX#K@klTvPUy%A8&%URz%!b$kfok#(>;iK5~CGOmtx2L z4Le5f+MEN=gp77x^xq_? zW|Dp2_Id=LP66b&@(8$znIZYbDQs|Cg`l>g{BzZlN#JuB9ErQss>g7IIkXBSW-WJ% zyppui?7aIqxp(ZH{6F;?U6CtktPIXVeM=L5 z4WC75*_;~o;CekJ(UE+s^_DkJgi>Vqs+;PvJ1EyNYrAK{Zv>G5k?G^@eqFh66-qV zzT*YFjSBqjrSB2(4@{vSoARL0tup~;clgATgtB}IA%Q&zt*}7?x(OQ_T9AOf>h{dA z!kil4w6z{i4Xyaxflr$2C+;Hz*|>-qPh5c`;XHfO-Q58nyWdy7-w*1J`j`P0SRrBS z5WsgWNT@s{hBu#!VwJEwnomNun%#X;A6R^jl_mL|U#z#*rK8AII=Mn;zn?4hA=hdg zxI~*cuoI0c*~z_kj3dkOxO&tlokscJI4Q7{`hGXQJ8X0TC>m<K&!6dhOe8zV%EzVlY?<-2> zc$6MvZN1!ol*E&-?UBI65XUvgt)0VOH6@Fne#>wI#JZh8*>7>N?h+qay2R-W87$XK z@8}~Wt7q`Qo85qrrPyx;6_rr;%+XUpu^^!noi#`fv6;Pp=U{^E<8pd);i4 zfa<_(z;_Aq{RgfVm1Ese5oE?q6cdmtE=PQ=61bOO4Akc1fdaa$)u5(7HYpQW`SA%AcR0X2ukM~wM+^4sIi2eJ)8 z6cfO9jL3eMYdh$4zTJ9vDEw*=LPgF9UWyN$&LGq?M*_U4{y1uLgcpqYBXIE^{N2R##`kTm96s*e z(Isj+A;5!?FEE88!BptqYAp0WW6TeD_3Z9oasO_7>>2tHvsM7r2BGa>cfgIOhPL$- z++61dS2F~_7<|E$>j!k<$e-y#|Ky7~0m0Nj8P~TCJ5lzwH#DW9q~1HIM<{aSRpI@9~>>TNzxQv-3-t@pf1uMt99x{Ep39kUE}w~IZoF)D=e z0}`MyQ_$Na*DE%PN~_=ZNk}4xjDb3uPr8qzbHq@a=E?K()@`oPctikIm>EcVEXyC! zjDfPGtibPul5D95H5f+2hr*R*`y|kG%!>p&Rt4A7hC)@c7tm|G!ANADCH~Qv=ePLm zZjqQ8Y@?~zQ*F$XK;=OnOj{x_X8Ax_3g&FR@McY>;ABmf_atgC4*<%g?yxA6E|gsV sWv}GQFMItmF7A>{r0$NpV^EL(0DGp^W~b0{$N&HU07*qoM6N<$f};FOa{vGU literal 0 HcmV?d00001 diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/rocket.png b/modules/cms-kit/src/Volo.CmsKit.Common.Web/wwwroot/cms-kit/icons/rocket.png new file mode 100644 index 0000000000000000000000000000000000000000..e72bb81025cfcad66404b9fec4a3607f36cab1d4 GIT binary patch literal 2984 zcmV;Z3s>}sP)qc!vaE-#a zFNiFP0*DCCadAAEHBU z)H#iUW;{0H@%}ST%br`}DwXO@wNe?L`@uMt;aq12C`D-hOHls^@B-vGIXr&?jXNd(a=ofo)C2?5($9Lnf2Td&(6*sjHI_9`8&C}xp48~MQCbj zf|hx+iBz9Jf{_5!FP;nX8jWU(QmJf1@=#u04tl*Fu3Wjoa5-X6p9P?vzX#Kub$YFZs^SPU!0DVz_qg8no@-*CzoAPyn1Fa|KKO^y$+hv$C=pQ2?l_s)FX` zX1IL$GPJk16JbXD=FOV~cHV*4TjtMsBJ$0M92ZAWIXUhXB>B|T)IVfqX6mu&5qYvb z)x3cK*RNlP?(S{^owIB0S}o`&yFFHb+TIyp^gO|l$E?4SmX=nH0YoHC5fu4dyLJssN=j0q08m(1 z2o)6-aOu(|sIIPty1F`OY;1&jbi$sPIPhC0gV|p!g(b2eIIc*i%oBNX2y+U1R+9%! zGd+#SH{759u?IM;5|jYPk00N0;=~D{dA_WyjO@?qU#HVi8Q`%R{JseUSI>DcafTO6 zoVoD+(Q__@Y~Dth=gE^}m~*O8z`Bj=K|jv9SAdHsfZD~OM>B5RTY@2f^ytx9hBJJtjawK>_aqTJjPBJTC*+>2rvz zNl-b=`aFPaPbEW{=gHF;M4pX_(<@-9>8alcLV$w@4{k(2Mn(q94sCE~xl2v({Q2_+ zB21dS5XlmZ1#m?N_uT9Q2!v?)4MbV zb5(M3G8{Q_q?ugzOo)qCq)o7sDbgj9zzAR`f|F;XU#YBh7hd}5abA643nUH^b9>q@6f-2GYnf%7{twVcU1Z+{ItRC*F%;*~(zZ$jl-)kPy5hcri?Z z?$I;!EbS-aT}7Z*oJLIEtf|7*zO zEwMZfkO(h@C}Dr>LBI`5RnS1u+0#qeTuJIB{BFY+f`ko;!y)I%`aM4mc*LPSJ_Sg_=g_@pV`OKPWh`@@!cCH!^%MU_*r_vJcCZrFYJMK>0sL!1?hbm&=Odr5COm9hBsmjBz?#qF$umdLHN3Y(807P;9cv0iJ$GvcfL=BX>c6n> z6`_(ua3c}$`1iM=Y2#4X81Ny?@%3$-;doRWV>uvo_=8em1jUAOTHrx z%^E5U0SZJ3SE~lWtt<(&%Iu-(YkR0)gd!|_Ai{-7_HZNA20Atl0$rdu2RQCYYnNPb z9KSR%@&iK(sP+N>-Yy984P}xcT8-%TFZzCPJ@O5>5^T>zX#QUjW{rT3;33ex+XA$! z#T_-@S-;8kA;f{Hp=5coJ_#{cnyPLPJ;ht?8$s;uC~j^WT5h9ay- z5mwtnN7(CdC(#;iBn$-IHgR`dxcFo4SA>mJ;YI=smML0nmS>IPgcNB1^S7G@z}<2Y z+>U<}ZXbIU?xYQdo;(Zq=^Qpi6hIpxuBqE*`yTfzW60V&{=H>Z538f zudxMfw)mDVLv*S(RlKk+lC$Do?(m0000Jo*S&-o-W?O~-HnTn-HnS+-HVAY?2d{r@5IE{`SsfXzxN}a z^J9K}g`Y3%#KjUnpW2Oy>pP=jp8sFr_uk?;f8f`@@&9k~d%t++HF4#CM$RGj$$N3} zRo>)JdE;^3*cQM3i8ptbpH=y9Y8Jck0PT&pQ7+YP=F^>2n2J&%(_ZMboh0zZnH6A?vIIDJ|V0^LQpX&=pZGiJR#_CQcxu=s5&L6HZ90x z;2F=q|M^@ZK&8nrRpz2(ET1In<}lH%%S3NJ|4^83T&7&Q)8hTqShGHKETsRL5S^@Y zFY%ZB+1V^MZWL3JL~SZS)=YqC76`iFJf8uC4J#ukKd#o{H75AkY=~$nN_1m@XyX~8 ztqVlAp99H9!n}2rcE{RG-rwwzk)|~f+8Yz^=S}{M7tYxyG$u?CHZvO0xi$@<#!&Ci z0zqg7$U`$A5Q&9$qUAoK_0vSJj}UEN0Xfeo&YmEc0`}cB>Ag|$0p8dz`LzGSqz!f2 zEC{NlwG&ok=Yg<;h{QrY)N?ftCyg~rDUCeVT8De^46 zAMyeg?6{ERg%Zj(q2>WaS|^NCbI`#AbaVoB&oBpb&H0G?^dVTxkpfsB@}>R?#kqd? zpb8~Kn}5ePD!zwJF>%Yv$W2w#4+LP$w7E#Th%R+Gh&F_JU(L^r2id#BcW6Su+SwkW z)j=XSzc(&{m@gl|k!YqFwZ8xl3iA4i7@44>{sBc?k*+73?RL;3v8*Ah(5+y9#+dJ< z{qX>=FEvg16>Gkos&idbo{dszCQA9KE*rUt4%$z((_S)6dx?hw5k4VtqhG^-j=J|SR|&*i?54tm6f%IYSVlj5{VdD%(h4a!R zZeM+<85moaSW6;yQUqr%ybh$C2yY;-oSahkTq4L$t4ky9A`OD8Cp8R8tT|X!Q145j z7)!m#@E9^tl71(E?}c_?E}{X5t3=2XtOxnPmLKoGl;g||ckt8mPAiE z;P}1X7KgGu z7vUjnSi>2Gy62b&Sp0cx@W34g@!b$K*51^jfKM2&U$WQdi12x@CXj^y>dCuKT_>(c zE3!9%vkr#gkWjqX&go#bhpJi5={MvY%r{wZ?mR%LzZ8H9gU|XTuR`J#(m<%SA=QvoP!azSqXFFER`2d(0(FxzoIKlcTsIclG{f(V-qmzOhDBF{rDcN zqwL=oDr>`117hM6-UW~hTKIC*~~9#5W~zN%%Yfo7Hd;uXxUa=;sXu9(a3> z+tsC$?5rFoIH85$`7nfl?}xzg9nb{NS)s9ck+m;mAeBc=;ME7LWgLxFU;9YPeJfJgcprg;{8EK0xL9KFUvasAnAWW%*p@w7W7L=7gw|YKuK&tPGI3 zIz-0WS*ooK^IGSq%BZXk)8X8n7O*?T%L*h+0O#t)+EJp~LzrQLv{0IOx?STdiNQV6N21@e-c4~}_(2D@pkeJZwL&@u^t`l!QPRCW5?dl0E zXyma62;E;i7_9vRBZ zG8-%=bQ4h7pe%-^Fo!-T8a#u;arSl@ z`>G3l=GJ9ibA%38&e(SZSPwT%;O8+4M67z%KQ{6Jvbg_DW?X;cz97flqI@!FH%E!Jd%1@|q~0DfCypSEN2(x9gL$44Ged3!0TxVsmEXhKM4>bDNKWJbfyvPFio$Zy!g9hsE z#}GO?O)eLCp%GG~W*`sIjTd?!>g~__#3gsWz*aZl_YFiwBSvY?ZkX<3&AY!6J-p@% zjF%Z>y!Km6>TO1zL5%===Xv+g)xu}RlOFih7k&(d90KiVzXHH1B6;z0rw`B0xx>Kz zsOX227XL2;8^T>2!>X>2_)Cdz$R45W;=YT=I|>H8XMRD4Ce+Xo9^ z1ooIqb(ns%V3&Oek}uH;gUis**!}+HA;vRpU5+Wj6X|O~4uFM99iEh^u zuid;z`KhSoocuCZg1w^E2LD?742QzMf+RdV2y+)1f2;0q9yNo^|66oGt(oNK;13wv oPNz4;=J6%;62;T;bUg9#Z%1_cOr6p&TmS$707*qoM6N<$g4cR~CIA2c literal 0 HcmV?d00001 diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Reactions/StandardReactions.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Reactions/StandardReactions.cs index db1a4ebaea..69a2d4c73a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Reactions/StandardReactions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Reactions/StandardReactions.cs @@ -2,7 +2,13 @@ { public static class StandardReactions { - public const string Smile = "SM"; - public const string ThumbsUp = "TU"; + public const string Smile = "_SM"; + public const string ThumbsUp = "_TU"; + public const string ThumbsDown = "_TD"; + public const string Confused = "_CF"; + public const string Eyes = "_EY"; + public const string Heart = "_HE"; + public const string Hooray = "_HO"; + public const string Rocket = "_RO"; } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs index 4fbdf07204..e67bca57df 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs @@ -16,6 +16,12 @@ namespace Volo.CmsKit { options.Reactions.AddOrReplace(StandardReactions.Smile); options.Reactions.AddOrReplace(StandardReactions.ThumbsUp); + options.Reactions.AddOrReplace(StandardReactions.ThumbsDown); + options.Reactions.AddOrReplace(StandardReactions.Confused); + options.Reactions.AddOrReplace(StandardReactions.Eyes); + options.Reactions.AddOrReplace(StandardReactions.Heart); + options.Reactions.AddOrReplace(StandardReactions.Hooray); + options.Reactions.AddOrReplace(StandardReactions.Rocket); }); } } 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 4a4ee6cfb5..adaa925a55 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,18 +1,19 @@ @model Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection.ReactionSelectionViewModel - + @foreach (var reaction in Model.Reactions.Where(r => r.Count > 0)) { - - @(reaction.Count) + + + @(reaction.Count) } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css index e984fa3d77..8e27846c5c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css @@ -5,9 +5,9 @@ .cms-reaction-icon { cursor: pointer; - padding: 2px; + padding: 3px 5px 5px; } .cms-reaction-icon-selected { - background-color: #eee; + background-color: #eef; } 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 62a060a543..7901557e72 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 @@ -4,8 +4,8 @@ var myDefaultWhiteList = $.fn.tooltip.Constructor.Default.whiteList; - if (myDefaultWhiteList.img.indexOf('data-name') < 0) { - myDefaultWhiteList['img'].push('data-name'); + if (myDefaultWhiteList.span.indexOf('data-reaction-name') < 0) { + myDefaultWhiteList.span.push('data-reaction-name'); } $(document).ready(function () { @@ -30,7 +30,7 @@ var methodName = $icon.hasClass('cms-reaction-icon-selected') ? 'delete' : 'create'; volo.cmsKit.reactions.reactionPublic[methodName]( $.extend(getFilters(), { - reactionName: $icon.attr('data-name') + reactionName: $icon.attr('data-reaction-name') }) ).then(function () { $selectIcon.popover('hide'); @@ -45,6 +45,7 @@ $selectIcon.popover({ placement: 'right', html: true, + trigger: 'focus', title: l('PickYourReaction'), content: $popoverContent.html() }).on('shown.bs.popover', function () { From 297f9540646e6070838cd001b532382f051d8db7 Mon Sep 17 00:00:00 2001 From: buaziz Date: Wed, 8 Jul 2020 14:33:38 +0300 Subject: [PATCH 066/376] Account --- .../Account/Localization/Resources/ar.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/ar.json diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/ar.json new file mode 100644 index 0000000000..2f7a9b9142 --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/ar.json @@ -0,0 +1,14 @@ +{ + "culture": "ar", + "texts": { + "Account": "حساب ABP - تسجيل الدخول وإنشاء حساب | ABP.IO", + "Welcome": "أهلا و سهلا", + "UseOneOfTheFollowingLinksToContinue": "استخدم أحد الروابط التالية للمتابعة", + "FrameworkHomePage": "الصفحة الرئيسية للنظام", + "FrameworkDocumentation": "وثائق النظام", + "OfficialBlog": "المدونة الرسمية", + "CommercialHomePage": "الصفحة الرئيسية للنظام التجاري", + "CommercialSupportWebSite": "موقع الدعم الفني للنظام التجاري", + "CommunityWebSite": "موقع مجتمع ABP" + } +} \ No newline at end of file From 16cc689f27a6782f60c63682346e309090f9ee4a Mon Sep 17 00:00:00 2001 From: buaziz Date: Thu, 9 Jul 2020 13:20:18 +0300 Subject: [PATCH 067/376] Admin --- .../Admin/Localization/Resources/ar.json | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json new file mode 100644 index 0000000000..96661aebeb --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json @@ -0,0 +1,161 @@ +{ + "culture": "ar", + "texts": { + "Permission:Organizations": "المنظمات", + "Permission:Manage": "إدارة المنظمات", + "Permission:DiscountRequests": "طلبات الخصم", + "Permission:DiscountManage": "إدارة طلبات الخصم", + "Permission:Disable": "تعطيل", + "Permission:Enable": "تفعيل", + "Permission:EnableSendEmail": "تمكين إرسال البريد الإلكتروني", + "Permission:SendEmail": "ارسل بريد الكتروني", + "Permission:NpmPackages": "حزم NPM", + "Permission:NugetPackages": "حزم Nuget", + "Permission:Maintenance": "صيانة", + "Permission:Maintain": "المحافظة", + "Permission:ClearCaches": "مسح ذاكرة التخزين المؤقت", + "Permission:Modules": "الوحدات", + "Permission:Packages": "حزم", + "Permission:Edit": "تعديل", + "Permission:Delete": "حذف", + "Permission:Create": "إنشاء", + "Permission:Accounting": "محاسبة", + "Permission:Accounting:Quotation": "عرض سعر", + "Permission:Accounting:Invoice": "فاتورة", + "Menu:Organizations": "المنظمات", + "Menu:Accounting": "المحاسبة", + "Menu:Packages": "الحزم", + "Menu:DiscountRequests": "طلبات الخصم", + "NpmPackageDeletionWarningMessage": "سيتم حذف حزمة NPM هذه. هل تؤكد ذلك؟", + "NugetPackageDeletionWarningMessage": "سيتم حذف حزمة Nuget هذه. هل تؤكد ذلك؟", + "ModuleDeletionWarningMessage": "سيتم حذف هذه الوحدة. هل تؤكد ذلك؟", + "Name": "اسم", + "DisplayName": "اسم العرض", + "ShortDescription": "وصف قصير", + "NameFilter": "الاسم", + "CreationTime": "وقت الإنشاء", + "IsPro": "هو pro", + "ShowOnModuleList": "إظهار في قائمة الوحدات", + "EfCoreConfigureMethodName": "تكوين اسم method", + "IsProFilter": "هو pro", + "ApplicationType": "نوع التطبيق", + "Target": "استهداف", + "TargetFilter": "استهداف", + "Edit": "تعديل", + "Delete": "حذف", + "Refresh": "تحديث", + "NpmPackages": "حزم NPM", + "NugetPackages": "حزم Nuget", + "NpmPackageCount": "عدد حزم NPM", + "NugetPackageCount": "عدد حزم Nuget", + "Module": "الوحدات", + "ModuleInfo": "معلومات الوحدة", + "CreateANpmPackage": "إنشاء حزمة NPM", + "CreateAModule": "إنشاء وحدة", + "CreateANugetPackage": "أنشاء حزمة Nuget", + "AddNew": "اضف جديد", + "PackageAlreadyExist{0}": "", + "ModuleAlreadyExist{0}": "", + "ClearCache": "مسح ذاكرة التخزين المؤقت", + "SuccessfullyCleared": "تم محوه بنجاح", + "Menu:NpmPackages": "حزم NPM", + "Menu:Modules": "الوحدات", + "Menu:Maintenance": "الصيانة", + "Menu:NugetPackages": "حزم Nuget", + "CreateAnOrganization": "إنشاء منظمة", + "Organizations": "المنظمات", + "LongName": "اسم طويل", + "LicenseType": "نوع الرخصة", + "MissingLicenseTypeField": "حقل نوع الرخصة مطلوب!", + "LicenseStartTime": "وقت بدء الرخصة", + "LicenseEndTime": "وقت إنتهاء الرخصة", + "AllowedDeveloperCount": "عدد مطوري البرامج المسموح به", + "UserNameOrEmailAddress": "اسم المستخدم أو البريد الالكتروني", + "AddOwner": "أضف مالك", + "UserName": "اسم المستخدم", + "Email": "البريد الإلكتروني", + "Developers": "المطورين", + "AddDeveloper": "أضف مطور", + "Create": "إنشاء", + "UserNotFound": "لم نعثر على المستخدم", + "{0}WillBeRemovedFromDevelopers": "{0} ستتم إزالته من المطورين ، هل تؤكد ذلك؟", + "{0}WillBeRemovedFromOwners": "{0} ستتم إزالته من المالكين ، هل تؤكد ذلك؟", + "Computers": "أجهزة الكمبيوتر", + "UniqueComputerId": "معرف الكمبيوتر", + "LastSeenDate": "تاريخ آخر ظهور", + "{0}Computer{1}WillBeRemovedFromRecords": "ستتم إزالة كمبيوتر {0} ({1}) من السجلات", + "OrganizationDeletionWarningMessage": "سيتم حذف المنظمة", + "DeletingLastOwnerWarningMessage": "يجب أن يكون للمنظمة مالك واحد على الأقل! لذلك لا يمكنك إزالة هذا المالك", + "This{0}AlreadyExistInThisOrganization": "هذا {0} موجود بالفعل في هذه المنظمة", + "AreYouSureYouWantToDeleteAllComputers": "هل أنت متأكد أنك تريد حذف جميع أجهزة الكمبيوتر؟", + "DeleteAll": "حذف الكل", + "DoYouWantToCreateNewUser": "هل تريد إنشاء مستخدم جديد؟", + "MasterModules": "الوحدات الرئيسية", + "OrganizationName": "اسم المنظمة", + "CreationDate": "تاريخ الإنشاء", + "LicenseStart": "تاريخ بدء الرخصة", + "LicenseEndDate": "تاريخ إنتهاء الرخصة", + "OrganizationNamePlaceholder": "اسم المنظمة ...", + "TotalQuestionCountPlaceholder": "إجمالي عدد الأسئلة ...", + "RemainingQuestionCountPlaceholder": "عدد الأسئلة المتبقية ...", + "LicenseTypePlaceholder": "نوع الرخصة...", + "CreationDatePlaceholder": "تاريخ الإنشاء...", + "LicenseStartDatePlaceholder": "تاريخ بدء الرخصة ...", + "LicenseEndDatePlaceholder": "تاريخ إنتهاء الرخصة ...", + "UsernameOrEmail": "اسم المستخدم أو البريد الالكتروني", + "UsernameOrEmailPlaceholder": "اسم المستخدم أو البريد الالكتروني...", + "Member": "عضو", + "PurchaseOrderNo": "طلب الشراء رقم", + "QuotationDate": "تاريخ عرض السعر", + "CompanyName": "اسم الشركة", + "CompanyAddress": "عنوان الشركة", + "Price": "السعر", + "DiscountText": "نص الخصم", + "DiscountQuantity": "كمية الخصم", + "DiscountPrice": "سعر الخصم", + "Quotation": "عرض السعر", + "ExtraText": "نص إضافي", + "ExtraAmount": "مبلغ إضافي", + "DownloadQuotation": "تنزيل عرض الأسعار", + "Invoice": "فاتورة", + "TaxNumber": "الرقم الضريبي", + "InvoiceNumber": "رقم الفاتورة", + "InvoiceDate": "تاريخ الفاتورة", + "InvoiceNote": "ملاحظة الفاتورة", + "Quantity": "كمية", + "AddProduct": "أضف منتج", + "AddProductWarning": "تحتاج إلى إضافة منتج!", + "TotalPrice": "السعر الكلي", + "Generate": "انشاء", + "MissingQuantityField": "حقل الكمية مطلوب!", + "MissingPriceField": "حقل السعر مطلوب!", + "CodeUsageStatus": "الحالة", + "Country": "الدولة", + "DeveloperCount": "عدد المطورين", + "RequestCode": "كود الطلب", + "WebSite": "موقع الكتروني", + "GithubUsername": "اسم مستخدم Github", + "PhoneNumber": "رقم الهاتف", + "ProjectDescription": "وصف المشروع", + "Referrer": "المُحيل", + "DiscountRequests": "طلب الخصم", + "Copylink": "انسخ الرابط", + "Disable": "تعطيل", + "Enable": "تفعيل", + "EnableSendEmail": "تمكين إرسال البريد الإلكتروني", + "SendEmail": "ارسل بريد الكتروني", + "SuccessfullyDisabled": "تم التعطيل بنجاح", + "SuccessfullyEnabled": "تم التفعيل بنجاح", + "EmailSent": "تم ارسال البريد الالكتروني", + "SuccessfullySent": "أرسلت بنجاح", + "SuccessfullyDeleted": "تم الحذف بنجاح", + "DiscountRequestDeletionWarningMessage": "سيتم حذف طلب الخصم", + "BusinessType": "نوع العمل", + "TotalQuestionCount": "إجمالي عدد الأسئلة", + "RemainingQuestionCount": "عدد الأسئلة المتبقية", + "TotalQuestionMustBeGreaterWarningMessage": "يجب أن يكون TotalQuestionCount أكبر من RemainingQuestionCount!", + "QuestionCountsMustBeGreaterThanZero": "يجب أن يكون TotalQuestionCount و RemainingQuestionCount صفرًا أو أكبر من الصفر!", + "UnlimitedQuestionCount": "عدد أسئلة غير محدود", + "Notes": "ملاحظات" + } +} \ No newline at end of file From 8280116f84826670d856930eab3411afce92eb88 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Sun, 19 Jul 2020 09:45:05 +0800 Subject: [PATCH 068/376] Update Authorization.md --- docs/en/Authorization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md index 1522fa586a..1ede9f7577 100644 --- a/docs/en/Authorization.md +++ b/docs/en/Authorization.md @@ -284,7 +284,7 @@ You may need to check a policy/permission on the client side. For ASP.NET Core M abp.auth.isGranted('MyPermissionName'); ``` -See [abp.auth](API/JavaScript-API/Auth.md) API documentation for details. +See [abp.auth](UI/AspNetCore/JavaScript-API/Index.md) API documentation for details. ## Permission Management From 4c1d2f89574fa60bb1d75a6bb3398a793579ebc1 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Sun, 19 Jul 2020 23:01:23 +0800 Subject: [PATCH 069/376] Make EfCoreRepository implement IAsyncEnumerable Resolve #4806 --- .../EntityFrameworkCore/EfCoreRepository.cs | 7 +++++- .../Repositories/Repository_Basic_Tests.cs | 24 ++++++++++++++++++- 2 files changed, 29 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 29f3726704..a56430f864 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 @@ -15,7 +15,7 @@ using Volo.Abp.Guids; namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore { - public class EfCoreRepository : RepositoryBase, IEfCoreRepository + public class EfCoreRepository : RepositoryBase, IEfCoreRepository, IAsyncEnumerable where TDbContext : IEfCoreDbContext where TEntity : class, IEntity { @@ -195,6 +195,11 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return query; } + public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()) + { + return DbSet.AsAsyncEnumerable().GetAsyncEnumerator(cancellationToken); + } + protected virtual void CheckAndSetId(TEntity entity) { if (entity is IEntity entityWithGuidId) diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/Repository_Basic_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/Repository_Basic_Tests.cs index bfa6b8532d..3d5d7b656b 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/Repository_Basic_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/Repository_Basic_Tests.cs @@ -1,9 +1,31 @@ -using Volo.Abp.TestApp.Testing; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Shouldly; +using Volo.Abp.TestApp.Testing; +using Xunit; namespace Volo.Abp.EntityFrameworkCore.Repositories { public class Repository_Basic_Tests : Repository_Basic_Tests { + [Fact] + public async Task EFCore_QueryableExtension_ToListAsync() + { + await WithUnitOfWorkAsync(async () => + { + var persons = await PersonRepository.ToListAsync(); + persons.Count.ShouldBeGreaterThan(0); + }); + } + [Fact] + public async Task EFCore_QueryableExtension_CountAsync() + { + await WithUnitOfWorkAsync(async () => + { + var count = await PersonRepository.CountAsync(); + count.ShouldBeGreaterThan(0); + }); + } } } From d133135cc510db31d0e9f49c1bc853c586846c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 19 Jul 2020 23:09:37 +0300 Subject: [PATCH 070/376] Cleanup CMS Kit --- .../CmsKit/Reactions/UserReactionConsts.cs | 1 + .../Reactions/ReactionDefinitionDictionary.cs | 3 +- .../Volo/CmsKit/Reactions/ReactionManager.cs | 14 ++--- .../Reactions/GetAvailableReactionsDto.cs | 7 --- .../CmsKit/Reactions/GetForSelectionDto.cs | 9 ---- .../CmsKit/Reactions/GetMyReactionsDto.cs | 9 ---- .../Reactions/GetReactionSummariesDto.cs | 9 ---- .../Reactions/IReactionPublicAppService.cs | 14 +---- .../CmsKit/Reactions/ReactionSummaryDto.cs | 9 ---- .../CmsKit/CmsKitPublicApplicationModule.cs | 1 - .../Reactions/ReactionPublicAppService.cs | 54 ++----------------- .../Reactions/ReactionPublicController.cs | 27 ++-------- .../ReactionSelectionViewComponent.cs | 7 +-- 13 files changed, 20 insertions(+), 144 deletions(-) delete mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetAvailableReactionsDto.cs delete mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetForSelectionDto.cs delete mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetMyReactionsDto.cs delete mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetReactionSummariesDto.cs delete mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/ReactionSummaryDto.cs diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Reactions/UserReactionConsts.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Reactions/UserReactionConsts.cs index 5e9f6d95eb..be9b10af1b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Reactions/UserReactionConsts.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Reactions/UserReactionConsts.cs @@ -5,6 +5,7 @@ public static int EntityTypeLength { get; set; } = 64; public static int EntityIdLength { get; set; } = 64; + public static int ReactionNameLength { get; set; } = 32; } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionDefinitionDictionary.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionDefinitionDictionary.cs index 1159abd38b..94ff90fa45 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionDefinitionDictionary.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionDefinitionDictionary.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; +using JetBrains.Annotations; using Volo.Abp.Localization; namespace Volo.CmsKit.Reactions { public class ReactionDefinitionDictionary : Dictionary { - public void AddOrReplace(string name, ILocalizableString displayName = null) + public void AddOrReplace([NotNull] string name, ILocalizableString displayName = null) { this[name] = new ReactionDefinition(name, displayName); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs index 7d36d79c21..01c83071cc 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs @@ -29,21 +29,21 @@ namespace Volo.CmsKit.Reactions [NotNull] string entityType, [NotNull] string entityId) { - var summaries = await UserReactionRepository.GetSummariesAsync(entityType, entityId); + var queryResultItems = await UserReactionRepository.GetSummariesAsync(entityType, entityId); var summaryDtos = new List(); - foreach (var summary in summaries) + foreach (var queryResultItem in queryResultItems) { - var summaryDto = new ReactionSummary + var summary = new ReactionSummary { - Count = summary.Count + Count = queryResultItem.Count }; //TODO: Get all definitions then filter here? var reactionDefinition = await ReactionDefinitionStore .GetReactionOrNullAsync( - summary.ReactionName, + queryResultItem.ReactionName, entityType ); @@ -52,9 +52,9 @@ namespace Volo.CmsKit.Reactions continue; } - summaryDto.Reaction = reactionDefinition; + summary.Reaction = reactionDefinition; - summaryDtos.Add(summaryDto); + summaryDtos.Add(summary); } return summaryDtos; diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetAvailableReactionsDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetAvailableReactionsDto.cs deleted file mode 100644 index 0b6ee20836..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetAvailableReactionsDto.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Volo.CmsKit.Reactions -{ - public class GetAvailableReactionsDto - { - public string EntityType { get; set; } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetForSelectionDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetForSelectionDto.cs deleted file mode 100644 index 51a4d101ad..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetForSelectionDto.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Volo.CmsKit.Reactions -{ - public class GetForSelectionDto - { - public string EntityType { get; set; } - - public string EntityId { get; set; } - } -} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetMyReactionsDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetMyReactionsDto.cs deleted file mode 100644 index f5f2362eb2..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetMyReactionsDto.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Volo.CmsKit.Reactions -{ - public class GetMyReactionsDto - { - public string EntityType { get; set; } - - public string EntityId { get; set; } - } -} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetReactionSummariesDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetReactionSummariesDto.cs deleted file mode 100644 index 354edbf0e9..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/GetReactionSummariesDto.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Volo.CmsKit.Reactions -{ - public class GetReactionSummariesDto - { - public string EntityType { get; set; } - - public string EntityId { get; set; } - } -} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/IReactionPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/IReactionPublicAppService.cs index bf184c3c4f..93fab4e345 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/IReactionPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/IReactionPublicAppService.cs @@ -6,19 +6,7 @@ namespace Volo.CmsKit.Reactions { public interface IReactionPublicAppService : IApplicationService { - Task> GetAvailableReactions( - GetAvailableReactionsDto input - ); - - Task> GetReactionSummariesAsync( - GetReactionSummariesDto input - ); - - Task> GetMyReactions( - GetMyReactionsDto input - ); - - Task> GetForSelectionAsync(GetForSelectionDto input); + Task> GetForSelectionAsync(string entityType, string entityId); Task CreateAsync(CreateReactionDto input); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/ReactionSummaryDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/ReactionSummaryDto.cs deleted file mode 100644 index 72d3007aaf..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Reactions/ReactionSummaryDto.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Volo.CmsKit.Reactions -{ - public class ReactionSummaryDto - { - public ReactionDto Reaction { get; set; } - - public int Count { get; set; } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/CmsKitPublicApplicationModule.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/CmsKitPublicApplicationModule.cs index 45849fd825..d968205a54 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/CmsKitPublicApplicationModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/CmsKitPublicApplicationModule.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Application; using Volo.Abp.AutoMapper; using Volo.Abp.Modularity; diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Reactions/ReactionPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Reactions/ReactionPublicAppService.cs index f5cdae199d..ab92d6b767 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Reactions/ReactionPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Reactions/ReactionPublicAppService.cs @@ -25,65 +25,21 @@ namespace Volo.CmsKit.Reactions ReactionManager = reactionManager; } - public virtual async Task> GetAvailableReactions( - GetAvailableReactionsDto input) + public virtual async Task> GetForSelectionAsync(string entityType, string entityId) { var reactionDefinitions = await ReactionManager .GetAvailableReactionsAsync( - input.EntityType + entityType ); - var reactionDtos = reactionDefinitions - .Select(ConvertToReactionDto) - .ToList(); - - return new ListResultDto(reactionDtos); - } - - public virtual async Task> GetReactionSummariesAsync(GetReactionSummariesDto input) - { - var summaries = await ReactionManager.GetSummariesAsync(input.EntityType, input.EntityId); - - var summaryDtos = summaries - .Select(summary => new ReactionSummaryDto - { - Count = summary.Count, - Reaction = ConvertToReactionDto(summary.Reaction) - }) - .ToList(); - - return new ListResultDto(summaryDtos); - } - - public virtual async Task> GetMyReactions(GetMyReactionsDto input) - { - var userReactions = await ReactionManager.GetUserReactionsAsync( - CurrentUser.GetId(), - input.EntityType, - input.EntityId - ); - - var reactionDtos = userReactions - .Select(ConvertToReactionDto) - .ToList(); - - return new ListResultDto(reactionDtos); - } - - public virtual async Task> GetForSelectionAsync(GetForSelectionDto input) - { - var reactionDefinitions = await ReactionManager - .GetAvailableReactionsAsync( - input.EntityType - ); var summaries = - (await ReactionManager.GetSummariesAsync(input.EntityType, input.EntityId)) + (await ReactionManager.GetSummariesAsync(entityType, entityId)) .ToDictionary(x => x.Reaction.Name, x => x.Count); var userReactions = await ReactionManager.GetUserReactionsAsync( CurrentUser.GetId(), - input.EntityType, - input.EntityId + entityType, + entityId ); var reactionDtos = new List(); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Reactions/ReactionPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Reactions/ReactionPublicController.cs index 2fead1398f..8b11a50a62 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Reactions/ReactionPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Reactions/ReactionPublicController.cs @@ -18,31 +18,10 @@ namespace Volo.CmsKit.Reactions } [HttpGet] - [Route("available")] - public virtual Task> GetAvailableReactions(GetAvailableReactionsDto input) + [Route("{entityType}/{entityId}")] + public virtual Task> GetForSelectionAsync(string entityType, string entityId) { - return ReactionPublicAppService.GetAvailableReactions(input); - } - - [HttpGet] - [Route("summaries")] - public virtual Task> GetReactionSummariesAsync(GetReactionSummariesDto input) - { - return ReactionPublicAppService.GetReactionSummariesAsync(input); - } - - [HttpGet] - [Route("my")] - public virtual Task> GetMyReactions(GetMyReactionsDto input) - { - return ReactionPublicAppService.GetMyReactions(input); - } - - [HttpGet] - [Route("selection")] //TODO: Consider to rename! - public virtual Task> GetForSelectionAsync(GetForSelectionDto input) - { - return ReactionPublicAppService.GetForSelectionAsync(input); + return ReactionPublicAppService.GetForSelectionAsync(entityType, entityId); } [HttpPut] 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 882baf51ed..bcbe24eff8 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 @@ -32,12 +32,7 @@ namespace Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection string entityType, string entityId) { - var result = await ReactionPublicAppService.GetForSelectionAsync( - new GetForSelectionDto - { - EntityType = entityType, - EntityId = entityId - }); + var result = await ReactionPublicAppService.GetForSelectionAsync(entityType, entityId); var viewModel = new ReactionSelectionViewModel { From e6ba0af734b0ba128956f424bbc6c9e1084d076c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 19 Jul 2020 23:28:56 +0300 Subject: [PATCH 071/376] Refactor the ReactionManager. --- .../DefaultReactionDefinitionStore.cs | 4 +- .../Reactions/IReactionDefinitionStore.cs | 7 +- .../Volo/CmsKit/Reactions/ReactionManager.cs | 81 +++++-------------- .../Reactions/ReactionPublicAppService.cs | 34 ++++---- 4 files changed, 39 insertions(+), 87 deletions(-) diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/DefaultReactionDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/DefaultReactionDefinitionStore.cs index cc0daa3b65..4c7d4e095c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/DefaultReactionDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/DefaultReactionDefinitionStore.cs @@ -15,12 +15,12 @@ namespace Volo.CmsKit.Reactions Options = options.Value; } - public virtual Task> GetAvailableReactionsAsync(string entityType) + public virtual Task> GetReactionsAsync(string entityType = null) { return Task.FromResult(Options.Reactions.Values.ToList()); } - public Task GetReactionOrNullAsync(string reactionName, string entityType) + public Task GetReactionOrNullAsync(string reactionName, string entityType = null) { return Task.FromResult(Options.Reactions.GetOrDefault(reactionName)); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IReactionDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IReactionDefinitionStore.cs index fa3cad8076..3c2dee7008 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IReactionDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IReactionDefinitionStore.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using JetBrains.Annotations; @@ -7,8 +6,8 @@ namespace Volo.CmsKit.Reactions { public interface IReactionDefinitionStore { - Task> GetAvailableReactionsAsync([CanBeNull] string entityType); + Task> GetReactionsAsync([CanBeNull] string entityType = null); - Task GetReactionOrNullAsync([NotNull] string reactionName, [CanBeNull] string entityType); + Task GetReactionOrNullAsync([NotNull] string reactionName, [CanBeNull] string entityType = null); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs index 01c83071cc..f3e7b70216 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using JetBrains.Annotations; using Volo.Abp; @@ -19,80 +20,34 @@ namespace Volo.CmsKit.Reactions ReactionDefinitionStore = reactionDefinitionStore; } - public virtual async Task> GetAvailableReactionsAsync( + public virtual async Task> GetReactionsAsync( [CanBeNull] string entityType = null) { - return await ReactionDefinitionStore.GetAvailableReactionsAsync(entityType); + return await ReactionDefinitionStore.GetReactionsAsync(entityType); } public virtual async Task> GetSummariesAsync( [NotNull] string entityType, [NotNull] string entityId) { - var queryResultItems = await UserReactionRepository.GetSummariesAsync(entityType, entityId); - - var summaryDtos = new List(); - - foreach (var queryResultItem in queryResultItems) - { - var summary = new ReactionSummary - { - Count = queryResultItem.Count - }; - - //TODO: Get all definitions then filter here? - var reactionDefinition = await ReactionDefinitionStore - .GetReactionOrNullAsync( - queryResultItem.ReactionName, - entityType - ); - - if (reactionDefinition == null) - { - continue; - } - - summary.Reaction = reactionDefinition; + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - summaryDtos.Add(summary); - } + var userReactionCounts = (await UserReactionRepository.GetSummariesAsync(entityType, entityId)) + .ToDictionary(x => x.ReactionName, x => x.Count); - return summaryDtos; - } - - public virtual async Task> GetUserReactionsAsync( - Guid userId, - [NotNull] string entityType, - [NotNull] string entityId) - { - var userReactions = await UserReactionRepository - .GetListForUserAsync( - userId, - entityType, - entityId + var reactions = await ReactionDefinitionStore + .GetReactionsAsync( + entityType ); - var reactionDtos = new List(); - - foreach (var userReaction in userReactions) - { - //TODO: Get all definitions then filter here? - var reactionDefinition = await ReactionDefinitionStore - .GetReactionOrNullAsync( - userReaction.ReactionName, - userReaction.EntityType - ); - - if (reactionDefinition == null) + return reactions + .Select(reaction => new ReactionSummary { - await UserReactionRepository.DeleteAsync(userReaction); - continue; - } - - reactionDtos.Add(reactionDefinition); - } - - return reactionDtos; + Reaction = reaction, + Count = userReactionCounts.GetOrDefault(reaction.Name) + }) + .ToList(); } public virtual async Task CreateAsync( @@ -129,6 +84,10 @@ namespace Volo.CmsKit.Reactions [NotNull] string entityId, [NotNull] string reactionName) { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); + Check.NotNullOrWhiteSpace(reactionName, nameof(reactionName)); + var existingReaction = await UserReactionRepository.FindAsync(userId, entityType, entityId, reactionName); if (existingReaction == null) { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Reactions/ReactionPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Reactions/ReactionPublicAppService.cs index ab92d6b767..f1b2aff260 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Reactions/ReactionPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Reactions/ReactionPublicAppService.cs @@ -27,36 +27,30 @@ namespace Volo.CmsKit.Reactions public virtual async Task> GetForSelectionAsync(string entityType, string entityId) { - var reactionDefinitions = await ReactionManager - .GetAvailableReactionsAsync( - entityType - ); - - var summaries = - (await ReactionManager.GetSummariesAsync(entityType, entityId)) - .ToDictionary(x => x.Reaction.Name, x => x.Count); + var summaries = await ReactionManager.GetSummariesAsync(entityType, entityId); - var userReactions = await ReactionManager.GetUserReactionsAsync( - CurrentUser.GetId(), - entityType, - entityId - ); + var userReactions = (await UserReactionRepository + .GetListForUserAsync( + CurrentUser.GetId(), + entityType, + entityId + )).ToDictionary(x => x.ReactionName, x => x); - var reactionDtos = new List(); + var reactionWithSelectionDtos = new List(); - foreach (var reactionDefinition in reactionDefinitions) + foreach (var summary in summaries) { - reactionDtos.Add( + reactionWithSelectionDtos.Add( new ReactionWithSelectionDto { - Reaction = ConvertToReactionDto(reactionDefinition), - Count = summaries.GetOrDefault(reactionDefinition.Name), - IsSelectedByCurrentUser = userReactions.Any(x => x.Name == reactionDefinition.Name) + Reaction = ConvertToReactionDto(summary.Reaction), + Count = summary.Count, + IsSelectedByCurrentUser = userReactions.ContainsKey(summary.Reaction.Name) } ); } - return new ListResultDto(reactionDtos); + return new ListResultDto(reactionWithSelectionDtos); } public virtual async Task CreateAsync(CreateReactionDto input) From a32b4fbb0d54a886cc87b6d13da4ea0146c68c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 19 Jul 2020 23:32:29 +0300 Subject: [PATCH 072/376] Refactor EfCoreUserReactionRepository --- .../Reactions/IUserReactionRepository.cs | 9 +++++++-- .../Reactions/EfCoreUserReactionRepository.cs | 20 +++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IUserReactionRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IUserReactionRepository.cs index 549982d404..2c964c70f5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IUserReactionRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IUserReactionRepository.cs @@ -14,8 +14,13 @@ namespace Volo.CmsKit.Reactions [NotNull] string entityId, [NotNull] string reactionName); - Task> GetListForUserAsync(Guid userId, string entityType, string entityId); + Task> GetListForUserAsync( + Guid userId, + [NotNull] string entityType, + [NotNull] string entityId); - Task> GetSummariesAsync(string entityType, string entityId); + Task> GetSummariesAsync( + [NotNull] string entityType, + [NotNull] string entityId); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs index 2ddd72bdd3..e29fe108c2 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; +using Volo.Abp; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using Volo.CmsKit.EntityFrameworkCore; @@ -23,6 +24,10 @@ namespace Volo.CmsKit.Reactions string entityId, string reactionName) { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); + Check.NotNullOrWhiteSpace(reactionName, nameof(reactionName)); + return await DbSet .Where(x => x.UserId == userId && @@ -32,8 +37,14 @@ namespace Volo.CmsKit.Reactions .FirstOrDefaultAsync(); } - public async Task> GetListForUserAsync(Guid userId, string entityType, string entityId) + public async Task> GetListForUserAsync( + Guid userId, + string entityType, + string entityId) { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); + return await DbSet .Where(x => x.UserId == userId && @@ -42,8 +53,13 @@ namespace Volo.CmsKit.Reactions .ToListAsync(); } - public async Task> GetSummariesAsync(string entityType, string entityId) + public async Task> GetSummariesAsync( + string entityType, + string entityId) { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); + return await DbSet .Where(x => x.EntityType == entityType && From 8592ed3f32e0b81907385eb65b83133b5b472516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 19 Jul 2020 23:47:45 +0300 Subject: [PATCH 073/376] Implement IHasCreationTime and IMustHaveCreator for the UserReaction. --- ... => 20200719204212_Added_Reactions.Designer.cs} | 14 ++++++++------ ...ctions.cs => 20200719204212_Added_Reactions.cs} | 10 +++++----- .../Migrations/UnifiedDbContextModelSnapshot.cs | 10 ++++++---- .../Volo/CmsKit/Reactions/ReactionManager.cs | 7 +++---- .../Volo/CmsKit/Reactions/UserReaction.cs | 13 ++++++------- .../CmsKitDbContextModelCreatingExtensions.cs | 2 +- .../Reactions/EfCoreUserReactionRepository.cs | 4 ++-- 7 files changed, 31 insertions(+), 29 deletions(-) rename modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/{20200715191733_Added_UserReactions.Designer.cs => 20200719204212_Added_Reactions.Designer.cs} (99%) rename modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/{20200715191733_Added_UserReactions.cs => 20200719204212_Added_Reactions.cs} (81%) diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200715191733_Added_UserReactions.Designer.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200719204212_Added_Reactions.Designer.cs similarity index 99% rename from modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200715191733_Added_UserReactions.Designer.cs rename to modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200719204212_Added_Reactions.Designer.cs index c5246843c6..71e8e68f91 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200715191733_Added_UserReactions.Designer.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200719204212_Added_Reactions.Designer.cs @@ -11,8 +11,8 @@ using Volo.CmsKit.EntityFrameworkCore; namespace Volo.CmsKit.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20200715191733_Added_UserReactions")] - partial class Added_UserReactions + [Migration("20200719204212_Added_Reactions")] + partial class Added_Reactions { protected override void BuildTargetModel(ModelBuilder modelBuilder) { @@ -921,8 +921,13 @@ namespace Volo.CmsKit.Migrations .HasColumnType("uniqueidentifier"); b.Property("CreationTime") + .HasColumnName("CreationTime") .HasColumnType("datetime2"); + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + b.Property("EntityId") .IsRequired() .HasColumnType("nvarchar(64)") @@ -938,14 +943,11 @@ namespace Volo.CmsKit.Migrations .HasColumnType("nvarchar(32)") .HasMaxLength(32); - b.Property("UserId") - .HasColumnType("uniqueidentifier"); - b.HasKey("Id"); b.HasIndex("EntityType", "EntityId"); - b.HasIndex("UserId", "EntityType", "EntityId", "ReactionName"); + b.HasIndex("CreatorId", "EntityType", "EntityId", "ReactionName"); b.ToTable("CmsUserReactions"); }); diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200715191733_Added_UserReactions.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200719204212_Added_Reactions.cs similarity index 81% rename from modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200715191733_Added_UserReactions.cs rename to modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200719204212_Added_Reactions.cs index 6e2e270763..c853458396 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200715191733_Added_UserReactions.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200719204212_Added_Reactions.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace Volo.CmsKit.Migrations { - public partial class Added_UserReactions : Migration + public partial class Added_Reactions : Migration { protected override void Up(MigrationBuilder migrationBuilder) { @@ -15,8 +15,8 @@ namespace Volo.CmsKit.Migrations EntityType = table.Column(maxLength: 64, nullable: false), EntityId = table.Column(maxLength: 64, nullable: false), ReactionName = table.Column(maxLength: 32, nullable: false), - CreationTime = table.Column(nullable: false), - UserId = table.Column(nullable: false) + CreatorId = table.Column(nullable: false), + CreationTime = table.Column(nullable: false) }, constraints: table => { @@ -29,9 +29,9 @@ namespace Volo.CmsKit.Migrations columns: new[] { "EntityType", "EntityId" }); migrationBuilder.CreateIndex( - name: "IX_CmsUserReactions_UserId_EntityType_EntityId_ReactionName", + name: "IX_CmsUserReactions_CreatorId_EntityType_EntityId_ReactionName", table: "CmsUserReactions", - columns: new[] { "UserId", "EntityType", "EntityId", "ReactionName" }); + columns: new[] { "CreatorId", "EntityType", "EntityId", "ReactionName" }); } protected override void Down(MigrationBuilder migrationBuilder) diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index e905ac9e66..35d92b2cc6 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -919,8 +919,13 @@ namespace Volo.CmsKit.Migrations .HasColumnType("uniqueidentifier"); b.Property("CreationTime") + .HasColumnName("CreationTime") .HasColumnType("datetime2"); + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + b.Property("EntityId") .IsRequired() .HasColumnType("nvarchar(64)") @@ -936,14 +941,11 @@ namespace Volo.CmsKit.Migrations .HasColumnType("nvarchar(32)") .HasMaxLength(32); - b.Property("UserId") - .HasColumnType("uniqueidentifier"); - b.HasKey("Id"); b.HasIndex("EntityType", "EntityId"); - b.HasIndex("UserId", "EntityType", "EntityId", "ReactionName"); + b.HasIndex("CreatorId", "EntityType", "EntityId", "ReactionName"); b.ToTable("CmsUserReactions"); }); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs index f3e7b70216..6f7fd6f00d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/ReactionManager.cs @@ -51,7 +51,7 @@ namespace Volo.CmsKit.Reactions } public virtual async Task CreateAsync( - Guid userId, + Guid creatorId, [NotNull] string entityType, [NotNull] string entityId, [NotNull] string reactionName) @@ -60,7 +60,7 @@ namespace Volo.CmsKit.Reactions Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); Check.NotNullOrWhiteSpace(reactionName, nameof(reactionName)); - var existingReaction = await UserReactionRepository.FindAsync(userId, entityType, entityId, reactionName); + var existingReaction = await UserReactionRepository.FindAsync(creatorId, entityType, entityId, reactionName); if (existingReaction != null) { return existingReaction; @@ -69,11 +69,10 @@ namespace Volo.CmsKit.Reactions return await UserReactionRepository.InsertAsync( new UserReaction( GuidGenerator.Create(), - userId, entityType, entityId, reactionName, - Clock.Now + creatorId ) ); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/UserReaction.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/UserReaction.cs index 34c3fa9bcd..4319739129 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/UserReaction.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/UserReaction.cs @@ -1,11 +1,12 @@ using System; using JetBrains.Annotations; using Volo.Abp; +using Volo.Abp.Auditing; using Volo.Abp.Domain.Entities; namespace Volo.CmsKit.Reactions { - public class UserReaction : Entity, IAggregateRoot + public class UserReaction : Entity, IAggregateRoot, IHasCreationTime, IMustHaveCreator { public virtual string EntityType { get; protected set; } @@ -13,9 +14,9 @@ namespace Volo.CmsKit.Reactions public virtual string ReactionName { get; protected set; } - public virtual DateTime CreationTime { get; protected set; } + public virtual Guid CreatorId { get; set; } - public virtual Guid UserId { get; protected set; } + public virtual DateTime CreationTime { get; set; } protected UserReaction() { @@ -24,18 +25,16 @@ namespace Volo.CmsKit.Reactions internal UserReaction( Guid id, - Guid userId, [NotNull] string entityType, [NotNull] string entityId, [NotNull] string reactionName, - DateTime creationTime) + Guid creatorId) : base(id) { EntityType = Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); EntityId = Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); ReactionName = Check.NotNullOrWhiteSpace(reactionName, nameof(reactionName)); - UserId = userId; - CreationTime = creationTime; + CreatorId = creatorId; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs index 7a12382e80..9eeb191f5b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs @@ -32,7 +32,7 @@ namespace Volo.CmsKit.EntityFrameworkCore b.Property(x => x.CreationTime); b.HasIndex(x => new { x.EntityType, x.EntityId }); - b.HasIndex(x => new { x.UserId, x.EntityType, x.EntityId, x.ReactionName }); + b.HasIndex(x => new { x.CreatorId, x.EntityType, x.EntityId, x.ReactionName }); }); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs index e29fe108c2..2d0b8ba989 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs @@ -30,7 +30,7 @@ namespace Volo.CmsKit.Reactions return await DbSet .Where(x => - x.UserId == userId && + x.CreatorId == userId && x.EntityType == entityType && x.EntityId == entityId && x.ReactionName == reactionName) @@ -47,7 +47,7 @@ namespace Volo.CmsKit.Reactions return await DbSet .Where(x => - x.UserId == userId && + x.CreatorId == userId && x.EntityType == entityType && x.EntityId == entityId) .ToListAsync(); From 849f7377995a80f1ad26f56d6ce07a5ffa585e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 20 Jul 2020 00:00:43 +0300 Subject: [PATCH 074/376] Move ReactionSelectionViewModel and ReactionViewModel into ReactionSelectionViewComponent as nested classes. --- .../ReactionSelection/Default.cshtml | 2 +- .../ReactionSelectionViewComponent.cs | 26 +++++++++++++++++++ .../ReactionSelectionViewModel.cs | 13 ---------- .../ReactionSelection/ReactionViewModel.cs | 21 --------------- 4 files changed, 27 insertions(+), 35 deletions(-) delete mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionSelectionViewModel.cs delete mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionViewModel.cs 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 adaa925a55..0f85f20fc6 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,4 +1,4 @@ -@model Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection.ReactionSelectionViewModel +@model Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection.ReactionSelectionViewComponent.ReactionSelectionViewModel