diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IOrganizationUnitRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IOrganizationUnitRepository.cs index a0ef631d2b..248e663413 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IOrganizationUnitRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IOrganizationUnitRepository.cs @@ -42,9 +42,23 @@ namespace Volo.Abp.Identity ); Task> GetRolesAsync( - Guid organizationUnitId, + OrganizationUnit organizationUnit, bool includeDetails = false, CancellationToken cancellationToken = default ); + + Task> GetMembersAsync( + OrganizationUnit organizationUnit, + string sorting = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + string filter = null, + bool includeDetails = false, + CancellationToken cancellationToken = default + ); + Task GetMembersCountAsync( + OrganizationUnit organizationUnit, + CancellationToken cancellationToken = default + ); } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs index dbb0304438..f00b69bb30 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore { } - public async Task> GetChildrenAsync( + public virtual async Task> GetChildrenAsync( Guid? parentId, bool includeDetails = false, CancellationToken cancellationToken = default) @@ -31,7 +31,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .ToListAsync(GetCancellationToken(cancellationToken)); } - public async Task> GetAllChildrenWithParentCodeAsync( + public virtual async Task> GetAllChildrenWithParentCodeAsync( string code, Guid? parentId, bool includeDetails = false, @@ -43,7 +43,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .ToListAsync(GetCancellationToken(cancellationToken)); } - public async Task> GetListAsync( + public virtual async Task> GetListAsync( string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, @@ -56,7 +56,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .PageBy(skipCount, maxResultCount) .ToListAsync(GetCancellationToken(cancellationToken)); } - public async Task> GetListAsync( + public virtual async Task> GetListAsync( IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) @@ -67,7 +67,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .ToListAsync(GetCancellationToken(cancellationToken)); } - public async Task GetAsync( + public virtual async Task GetAsync( string displayName, bool includeDetails = true, CancellationToken cancellationToken = default) @@ -78,22 +78,65 @@ namespace Volo.Abp.Identity.EntityFrameworkCore ou => ou.DisplayName == displayName, GetCancellationToken(cancellationToken) ); - } - public async Task> GetRolesAsync( - Guid organizationUnitId, bool includeDetails = false, + } + + public virtual async Task> GetRolesAsync( + OrganizationUnit organizationUnit, + bool includeDetails = false, CancellationToken cancellationToken = default) { var query = from organizationRole in DbContext.Set() join role in DbContext.Roles.IncludeDetails(includeDetails) on organizationRole.RoleId equals role.Id - where organizationRole.OrganizationUnitId == organizationUnitId + where organizationRole.OrganizationUnitId == organizationUnit.Id select role; return await query.ToListAsync(GetCancellationToken(cancellationToken)); } + public virtual async Task> GetMembersAsync( + OrganizationUnit organizationUnit, + string sorting = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + string filter = null, + bool includeDetails = false, + CancellationToken cancellationToken = default + ) + { + var query = from userOu in DbContext.Set() + join user in DbContext.Users.IncludeDetails(includeDetails) on userOu.UserId equals user.Id + where userOu.OrganizationUnitId == organizationUnit.Id + select user; + + if (!filter.IsNullOrWhiteSpace()) + { + query = query.Where(u => + u.UserName.Contains(filter) || + u.Email.Contains(filter) || + (u.PhoneNumber != null && u.PhoneNumber.Contains(filter)) + ); + } + + return await query.OrderBy(sorting ?? nameof(IdentityUser.UserName)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task GetMembersCountAsync( + OrganizationUnit organizationUnit, + CancellationToken cancellationToken = default) + { + var query = from userOu in DbContext.Set() + join user in DbContext.Users on userOu.UserId equals user.Id + where userOu.OrganizationUnitId == organizationUnit.Id + select user; + + return await query.CountAsync(GetCancellationToken(cancellationToken)); + } + public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); - } + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs index bc7cdcda91..102096f79f 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.Identity.MongoDB { } - public async Task> GetChildrenAsync( + public virtual async Task> GetChildrenAsync( Guid? parentId, bool includeDetails = false, CancellationToken cancellationToken = default) @@ -29,7 +29,7 @@ namespace Volo.Abp.Identity.MongoDB .ToListAsync(GetCancellationToken(cancellationToken)); } - public async Task> GetAllChildrenWithParentCodeAsync( + public virtual async Task> GetAllChildrenWithParentCodeAsync( string code, Guid? parentId, bool includeDetails = false, @@ -40,7 +40,7 @@ namespace Volo.Abp.Identity.MongoDB .ToListAsync(GetCancellationToken(cancellationToken)); } - public async Task> GetListAsync( + public virtual async Task> GetListAsync( IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) @@ -50,7 +50,7 @@ namespace Volo.Abp.Identity.MongoDB .ToListAsync(GetCancellationToken(cancellationToken)); } - public async Task> GetListAsync( + public virtual async Task> GetListAsync( string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, @@ -64,7 +64,7 @@ namespace Volo.Abp.Identity.MongoDB .ToListAsync(GetCancellationToken(cancellationToken)); } - public async Task GetAsync( + public virtual async Task GetAsync( string displayName, bool includeDetails = true, CancellationToken cancellationToken = default) @@ -76,14 +76,43 @@ namespace Volo.Abp.Identity.MongoDB ); } - public async Task> GetRolesAsync( - Guid organizationUnitId, + public virtual async Task> GetRolesAsync( + OrganizationUnit organizationUnit, bool includeDetails = false, CancellationToken cancellationToken = default) { - var organizationUnit = await GetAsync(organizationUnitId, includeDetails, cancellationToken); var roleIds = organizationUnit.Roles.Select(r => r.RoleId).ToArray(); return await DbContext.Roles.AsQueryable().Where(r => roleIds.Contains(r.Id)).ToListAsync(cancellationToken); - } + } + public virtual async Task> GetMembersAsync( + OrganizationUnit organizationUnit, + string sorting = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + string filter = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + return await DbContext.Users.AsQueryable() + .Where(u => u.OrganizationUnits.Any(uou => uou.OrganizationUnitId == organizationUnit.Id)) + .WhereIf>( + !filter.IsNullOrWhiteSpace(), + u => + u.UserName.Contains(filter) || + u.Email.Contains(filter) + ) + .OrderBy(sorting ?? nameof(IdentityUser.UserName)) + .As>() + .PageBy>(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task GetMembersCountAsync(OrganizationUnit organizationUnit, CancellationToken cancellationToken = default) + { + return await DbContext.Users.AsQueryable() + .Where(u => u.OrganizationUnits.Any(uou => uou.OrganizationUnitId == organizationUnit.Id)) + .As>() + .CountAsync(GetCancellationToken(cancellationToken)); + } } } 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 8999a9615a..9258be16af 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 @@ -119,6 +119,7 @@ namespace Volo.Abp.Identity var neo = new IdentityUser(_testData.UserNeoId, "neo", "neo@abp.io"); neo.AddRole(_supporterRole.Id); neo.AddClaim(_guidGenerator, new Claim("TestClaimType", "43")); + neo.AddOrganizationUnit(_ou111.Id); await _userRepository.InsertAsync(neo); } diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/OrganizationUnitRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/OrganizationUnitRepository_Tests.cs index fb06743500..1b8dac865a 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/OrganizationUnitRepository_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/OrganizationUnitRepository_Tests.cs @@ -84,20 +84,53 @@ namespace Volo.Abp.Identity { OrganizationUnit ou = await _organizationUnitRepository.GetAsync("OU111", true); - var ou111Roles = await _organizationUnitRepository.GetRolesAsync(ou.Id, true); + var ou111Roles = await _organizationUnitRepository.GetRolesAsync(ou, true); ou111Roles.Count.ShouldBe(2); ou111Roles.ShouldContain(n => n.Name == "manager"); ou111Roles.ShouldContain(n => n.Name == "moderator"); } [Fact] - public async Task GetUsersInOrganizationUnitListAsync() + public async Task GetMembersInOrganizationUnitListAsync() { OrganizationUnit ou1 = await _organizationUnitRepository.GetAsync("OU111", true); OrganizationUnit ou2 = await _organizationUnitRepository.GetAsync("OU112", true); var users = await _identityUserRepository.GetUsersInOrganizationsListAsync(new List { ou1.Id, ou2.Id }); - //var dodo = users.ToDictionary(u => u.Id, u => u); users.Count.ShouldBeGreaterThan(0); } + [Fact] + public async Task GetMembersInOrganizationUnitWithParamsAsync() + { + OrganizationUnit ou = await _organizationUnitRepository.GetAsync("OU111", true); + var users = await _organizationUnitRepository.GetMembersAsync(ou, "UserName DESC", 5, 0, "n"); + + users.Count.ShouldBeGreaterThan(1); + users.Count.ShouldBeLessThanOrEqualTo(5); + + //Filter check + users.ShouldAllBe(u => u.UserName.Contains("ne") || u.Email.Contains("n")); + + //Order check + for (var i = 0; i < users.Count - 1; i++) + { + string.Compare( + users[i].UserName, + users[i + 1].UserName, + StringComparison.OrdinalIgnoreCase + ).ShouldBeGreaterThan(0); + } + + users = await _organizationUnitRepository.GetMembersAsync(ou, null, 999, 0, "undefined-username"); + users.Count.ShouldBe(0); + } + + [Fact] + public async Task GetCountMembersCountInOrganizationUnit() + { + OrganizationUnit ou = await _organizationUnitRepository.GetAsync("OU111", true); + var users = await _organizationUnitRepository.GetMembersCountAsync(ou); + + users.ShouldBeGreaterThan(1); + } } }