From 23f304253674e2313c6793aa00bb284940ace568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 14 May 2020 04:11:03 +0300 Subject: [PATCH] Implemented SearchAsync for the user lookup --- .../Identity/IIdentityUserLookupAppService.cs | 3 ++ .../Abp/Identity/UserLookupSearchInputDto.cs | 11 ++++++ .../Identity/IdentityUserLookupAppService.cs | 17 +++++++++ ...sitoryExternalUserLookupServiceProvider.cs | 19 ++++++++++ .../HttpClientIdentityUserLookupService.cs | 19 ++++++++++ .../Identity/IdentityUserLookupController.cs | 8 +++++ .../IdentityUserLookupAppService_Tests.cs | 35 +++++++++++++++++-- .../IExternalUserLookupServiceProvider.cs | 9 ++++- .../Volo/Abp/Users/IUserLookupService.cs | 7 +++- .../Volo/Abp/Users/IUserRepository.cs | 8 +++++ .../Volo/Abp/Users/UserLookupService.cs | 13 +++++++ .../EfCoreAbpUserRepositoryBase.cs | 20 +++++++++++ .../Users/MongoDB/MongoUserRepositoryBase.cs | 17 +++++++++ 13 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UserLookupSearchInputDto.cs diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserLookupAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserLookupAppService.cs index 1ab79f400e..f3c3a3bc53 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserLookupAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserLookupAppService.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Users; @@ -10,5 +11,7 @@ namespace Volo.Abp.Identity Task FindByIdAsync(Guid id); Task FindByUserNameAsync(string userName); + + Task> SearchAsync(UserLookupSearchInputDto input); } } diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UserLookupSearchInputDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UserLookupSearchInputDto.cs new file mode 100644 index 0000000000..a2413e64ea --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UserLookupSearchInputDto.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Application.Dtos; + +namespace Volo.Abp.Identity +{ + public class UserLookupSearchInputDto : LimitedResultRequestDto, ISortedResultRequest + { + public string Sorting { get; set; } + + public string Filter { get; set; } + } +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserLookupAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserLookupAppService.cs index 48d42c4579..696ce864ce 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserLookupAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserLookupAppService.cs @@ -1,6 +1,8 @@ using System; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; +using Volo.Abp.Application.Dtos; using Volo.Abp.Users; namespace Volo.Abp.Identity @@ -37,5 +39,20 @@ namespace Volo.Abp.Identity return new UserData(userData); } + + public async Task> SearchAsync(UserLookupSearchInputDto input) + { + var users = await UserLookupServiceProvider.SearchAsync( + input.Sorting, + input.Filter, + input.MaxResultCount + ); + + return new ListResultDto( + users + .Select(u => new UserData(u)) + .ToList() + ); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserRepositoryExternalUserLookupServiceProvider.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserRepositoryExternalUserLookupServiceProvider.cs index 7fe729b325..9d8cd1dab4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserRepositoryExternalUserLookupServiceProvider.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserRepositoryExternalUserLookupServiceProvider.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; @@ -45,5 +47,22 @@ namespace Volo.Abp.Identity ) )?.ToAbpUserData(); } + + public virtual async Task> SearchAsync( + string sorting, + string filter, + int maxResultCount, + CancellationToken cancellationToken = default) + { + var users = await UserRepository.GetListAsync( + sorting: sorting, + maxResultCount: maxResultCount, + filter: filter, + includeDetails: false, + cancellationToken: cancellationToken + ); + + return users.Select(u => u.ToAbpUserData()).ToList(); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientIdentityUserLookupService.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientIdentityUserLookupService.cs index ec1dca264f..6d5fdd0f92 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientIdentityUserLookupService.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientIdentityUserLookupService.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; @@ -25,5 +27,22 @@ namespace Volo.Abp.Identity { return await UserLookupAppService.FindByUserNameAsync(userName); } + + public async Task> SearchAsync( + string sorting, + string filter, + int maxResultCount, + CancellationToken cancellationToken = default) + { + var result = await UserLookupAppService.SearchAsync( + new UserLookupSearchInputDto + { + Filter = filter, + MaxResultCount = maxResultCount + } + ); + + return result.Items.Cast().ToList(); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserLookupController.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserLookupController.cs index 2f8011bf7f..70dcaaa300 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserLookupController.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserLookupController.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Users; @@ -32,5 +33,12 @@ namespace Volo.Abp.Identity { return LookupAppService.FindByUserNameAsync(userName); } + + [HttpGet] + [Route("search")] + public Task> SearchAsync(UserLookupSearchInputDto input) + { + return LookupAppService.SearchAsync(input); + } } } diff --git a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserLookupAppService_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserLookupAppService_Tests.cs index 227977cf15..fc5a18cbd3 100644 --- a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserLookupAppService_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserLookupAppService_Tests.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Shouldly; @@ -52,5 +50,38 @@ namespace Volo.Abp.Identity var user = await _identityUserLookupAppService.FindByUserNameAsync(Guid.NewGuid().ToString()); user.ShouldBeNull(); } + + [Fact] + public async Task Search_Without_Filter_And_Sorting() + { + var result = await _identityUserLookupAppService.SearchAsync(new UserLookupSearchInputDto()); + result.Items.Count.ShouldBeGreaterThanOrEqualTo(3); + result.Items.ShouldContain(u => u.UserName == "john.nash"); + } + + [Fact] + public async Task Search_With_Filter() + { + var result = await _identityUserLookupAppService.SearchAsync( + new UserLookupSearchInputDto + { + Filter = "a" + } + ); + + result.Items.Count.ShouldBeGreaterThanOrEqualTo(2); + result.Items.ShouldContain(u => u.UserName == "john.nash"); + result.Items.ShouldContain(u => u.UserName == "david"); + + result = await _identityUserLookupAppService.SearchAsync( + new UserLookupSearchInputDto + { + Filter = "neo" + } + ); + + result.Items.Count.ShouldBeGreaterThanOrEqualTo(1); + result.Items.ShouldContain(u => u.UserName == "neo"); + } } } diff --git a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IExternalUserLookupServiceProvider.cs b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IExternalUserLookupServiceProvider.cs index 8f498e32c3..b973033be6 100644 --- a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IExternalUserLookupServiceProvider.cs +++ b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IExternalUserLookupServiceProvider.cs @@ -1,13 +1,20 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Volo.Abp.Users { - public interface IExternalUserLookupServiceProvider //TODO: Consider to inherit from IUserLookupService + public interface IExternalUserLookupServiceProvider { Task FindByIdAsync(Guid id, CancellationToken cancellationToken = default); Task FindByUserNameAsync(string userName, CancellationToken cancellationToken = default); + + Task> SearchAsync( + string sorting, + string filter, + int maxResultCount, + CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUserLookupService.cs b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUserLookupService.cs index 2c50d7795f..44e84eb350 100644 --- a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUserLookupService.cs +++ b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUserLookupService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -11,6 +12,10 @@ namespace Volo.Abp.Users Task FindByUserNameAsync(string userName, CancellationToken cancellationToken = default); - //TODO: More... + Task> SearchAsync( + string sorting, + string filter, + int maxResultCount, + CancellationToken cancellationToken = default); } } diff --git a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUserRepository.cs b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUserRepository.cs index 14eea6a3fe..fc0412c734 100644 --- a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUserRepository.cs +++ b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUserRepository.cs @@ -13,5 +13,13 @@ namespace Volo.Abp.Users Task FindByUserNameAsync(string userName, CancellationToken cancellationToken = default); Task> GetListAsync(IEnumerable ids, CancellationToken cancellationToken = default); + + Task> SearchAsync( + string sorting = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + string filter = null, + CancellationToken cancellationToken = default + ); } } \ No newline at end of file diff --git a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs index 2c28d71b80..7621f3f63e 100644 --- a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs +++ b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -138,6 +140,17 @@ namespace Volo.Abp.Users return await _userRepository.FindAsync(externalUser.Id, cancellationToken: cancellationToken); } + public async Task> SearchAsync(string sorting, string filter, int maxResultCount, CancellationToken cancellationToken = default) + { + if (ExternalUserLookupServiceProvider != null) + { + return await ExternalUserLookupServiceProvider.SearchAsync(sorting, filter, maxResultCount, cancellationToken); + } + + var localUsers = await _userRepository.SearchAsync(sorting, maxResultCount, 0, filter, cancellationToken); + return localUsers.Cast().ToList(); + } + protected abstract TUser CreateUser(IUserData externalUser); private async Task WithNewUowAsync(Func func) diff --git a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs index 5d0958101c..f5eb013c93 100644 --- a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs +++ b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq.Dynamic.Core; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -28,5 +29,24 @@ namespace Volo.Abp.Users.EntityFrameworkCore { return await DbSet.Where(u => ids.Contains(u.Id)).ToListAsync(GetCancellationToken(cancellationToken)); } + + public async Task> SearchAsync( + string sorting = null, + int maxResultCount = Int32.MaxValue, + int skipCount = 0, + string filter = null, + CancellationToken cancellationToken = default) + { + return await DbSet + .WhereIf( + !filter.IsNullOrWhiteSpace(), + u => + u.UserName.Contains(filter) || + u.Email.Contains(filter) + ) + .OrderBy(sorting ?? nameof(IUser.UserName)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } } } \ No newline at end of file diff --git a/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs b/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs index 50d892d8dd..3cb6e567ae 100644 --- a/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs +++ b/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; @@ -29,5 +30,21 @@ namespace Volo.Abp.Users.MongoDB { return await GetMongoQueryable().Where(u => ids.Contains(u.Id)).ToListAsync(GetCancellationToken(cancellationToken)); } + + public async Task> SearchAsync(string sorting = null, int maxResultCount = Int32.MaxValue, int skipCount = 0, string filter = null, + CancellationToken cancellationToken = default) + { + return await GetMongoQueryable() + .WhereIf>( + !filter.IsNullOrWhiteSpace(), + u => + u.UserName.Contains(filter) || + u.Email.Contains(filter) + ) + .OrderBy(sorting ?? nameof(IUserData.UserName)) + .As>() + .PageBy>(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } } } \ No newline at end of file