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 6650f62c82..81474425db 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 @@ -55,6 +55,14 @@ namespace Volo.Abp.Identity CancellationToken cancellationToken = default ); + Task> GetUnaddedRolesAsync( + OrganizationUnit organizationUnit, + string filter = null, + string sorting = null, + bool includeDetails = false, + CancellationToken cancellationToken = default + ); + Task> GetMembersAsync( OrganizationUnit organizationUnit, string sorting = null, @@ -71,6 +79,14 @@ namespace Volo.Abp.Identity CancellationToken cancellationToken = default ); + Task> GetUnaddedUsersAsync( + OrganizationUnit organizationUnit, + string filter = null, + string sorting = null, + bool includeDetails = false, + CancellationToken cancellationToken = default + ); + Task RemoveAllRolesAsync( OrganizationUnit organizationUnit, CancellationToken cancellationToken = default diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnit.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnit.cs index 3d1bbb0531..981a0f8fae 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnit.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnit.cs @@ -23,16 +23,16 @@ namespace Volo.Abp.Identity /// /// Hierarchical Code of this organization unit. /// Example: "00001.00042.00005". - /// This is a unique code for a Tenant. + /// This is a unique code for an OrganizationUnit. /// It's changeable if OU hierarchy is changed. /// public virtual string Code { get; internal set; } /// - /// Display name of this role. + /// Display name of this OrganizationUnit. /// - public virtual string DisplayName { get; set; } - + public virtual string DisplayName { get; set; } + /// /// Roles of this OU. /// @@ -77,7 +77,7 @@ namespace Volo.Abp.Identity } /// - /// Appends a child code to a parent code. + /// Appends a child code to a parent code. /// Example: if parentCode = "00001", childCode = "00042" then returns "00001.00042". /// /// Parent code. Can be null or empty if parent is a root. 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 7bdb7d6837..d50745ab1d 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 @@ -12,7 +12,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore { public class EfCoreOrganizationUnitRepository : EfCoreRepository, - IOrganizationUnitRepository + IOrganizationUnitRepository { public EfCoreOrganizationUnitRepository( IDbContextProvider dbContextProvider) @@ -56,6 +56,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .PageBy(skipCount, maxResultCount) .ToListAsync(GetCancellationToken(cancellationToken)); } + public virtual async Task> GetListAsync( IEnumerable ids, bool includeDetails = false, @@ -111,6 +112,23 @@ namespace Volo.Abp.Identity.EntityFrameworkCore return await query.CountAsync(GetCancellationToken(cancellationToken)); } + public virtual async Task> GetUnaddedRolesAsync( + OrganizationUnit organizationUnit, + string filter = null, + string sorting = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var roleIds = organizationUnit.Roles.Select(r => r.RoleId).ToList(); + + return await DbContext.Roles + .Where(r => !roleIds.Contains(r.Id)) + .IncludeDetails(includeDetails) + .WhereIf(!filter.IsNullOrWhiteSpace(), r => r.Name.Contains(filter)) + .OrderBy(sorting ?? nameof(IdentityRole.Name)) + .ToListAsync(cancellationToken); + } + public virtual async Task> GetMembersAsync( OrganizationUnit organizationUnit, string sorting = null, @@ -118,8 +136,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore int skipCount = 0, string filter = null, bool includeDetails = false, - CancellationToken cancellationToken = default - ) + CancellationToken cancellationToken = default) { var query = CreateGetMembersFilteredQuery(organizationUnit, filter); @@ -138,6 +155,35 @@ namespace Volo.Abp.Identity.EntityFrameworkCore return await query.CountAsync(GetCancellationToken(cancellationToken)); } + public virtual async Task> GetUnaddedUsersAsync( + OrganizationUnit organizationUnit, + string filter = null, + string sorting = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var userIdsInOrganizationUnit = DbContext.Set() + .Where(uou => uou.OrganizationUnitId == organizationUnit.Id) + .Select(uou => uou.UserId); + + var query = DbContext.Users + .Where(u => !userIdsInOrganizationUnit.Contains(u.Id)); + + 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 + .IncludeDetails(includeDetails) + .OrderBy(sorting ?? nameof(IdentityUser.Name)) + .ToListAsync(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 8c163d4126..2823c99a6c 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 @@ -107,6 +107,22 @@ namespace Volo.Abp.Identity.MongoDB .CountAsync(cancellationToken); } + public async Task> GetUnaddedRolesAsync( + OrganizationUnit organizationUnit, + string filter = null, + string sorting = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var roleIds = organizationUnit.Roles.Select(r => r.RoleId).ToArray(); + return await DbContext.Roles.AsQueryable() + .Where(r => !roleIds.Contains(r.Id)) + .WhereIf(!filter.IsNullOrWhiteSpace(), r => r.Name.Contains(filter)) + .OrderBy(sorting ?? nameof(IdentityRole.Name)) + .As>() + .ToListAsync(cancellationToken); + } + public virtual async Task> GetMembersAsync( OrganizationUnit organizationUnit, string sorting = null, @@ -135,6 +151,27 @@ namespace Volo.Abp.Identity.MongoDB return await query.CountAsync(GetCancellationToken(cancellationToken)); } + public async Task> GetUnaddedUsersAsync( + OrganizationUnit organizationUnit, + string filter = null, + string sorting = 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) || + (u.PhoneNumber != null && u.PhoneNumber.Contains(filter)) + ) + .OrderBy(sorting ?? nameof(IdentityUser.UserName)) + .As>() + .ToListAsync(GetCancellationToken(cancellationToken)); + } + public virtual Task RemoveAllRolesAsync(OrganizationUnit organizationUnit, CancellationToken cancellationToken = default) { organizationUnit.Roles.Clear(); 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 bb8300d449..97544cd1e9 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 @@ -284,5 +284,26 @@ namespace Volo.Abp.Identity await uow.CompleteAsync(); } } + + [Fact] + public async Task GetUnaddedUsersOfOrganizationUnitAsync() + { + var ou = await _organizationUnitRepository.GetAsync("OU111", true); + var unaddedUsers = await _organizationUnitRepository.GetUnaddedUsersAsync(ou); + + unaddedUsers.ShouldNotContain(u => u.UserName == "john.nash"); + unaddedUsers.ShouldContain(u => u.UserName == "administrator"); + } + + [Fact] + public async Task GetUnaddedRolesOfOrganizationUnitAsync() + { + var ou = await _organizationUnitRepository.GetAsync("OU111", true); + var unaddedRoles = await _organizationUnitRepository.GetUnaddedRolesAsync(ou); + + unaddedRoles.ShouldNotContain(u => u.Name == "manager"); + unaddedRoles.ShouldNotContain(u => u.Name == "moderator"); + unaddedRoles.ShouldContain(u => u.Name.Contains("admin")); + } } }