diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs index d8b3543703..29d6af4e3f 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs @@ -131,4 +131,16 @@ public interface IIdentityUserRepository : IBasicRepository bool includeDetails = false, CancellationToken cancellationToken = default ); + + Task UpdateRoleAsync( + Guid sourceRoleId, + Guid? targetRoleId, + CancellationToken cancellationToken = default + ); + + Task UpdateOrganizationAsync( + Guid sourceOrganizationId, + Guid? targetOrganizationId, + CancellationToken cancellationToken = default + ); } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs index 2dc1963505..8e6e9cba6c 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -356,4 +356,32 @@ public class EfCoreIdentityUserRepository : EfCoreRepository ids.Contains(x.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); } + + public virtual async Task UpdateRoleAsync(Guid sourceRoleId, Guid? targetRoleId, CancellationToken cancellationToken = default) + { + if (targetRoleId != null) + { + var users = await (await GetDbContextAsync()).Set().Where(x => x.RoleId == targetRoleId).Select(x => x.UserId).ToArrayAsync(cancellationToken: cancellationToken); + await (await GetDbContextAsync()).Set().Where(x => x.RoleId == sourceRoleId && !users.Contains(x.UserId)).ExecuteUpdateAsync(t => t.SetProperty(e => e.RoleId, targetRoleId), GetCancellationToken(cancellationToken)); + await (await GetDbContextAsync()).Set().Where(x => x.RoleId == sourceRoleId).ExecuteDeleteAsync(GetCancellationToken(cancellationToken)); + } + else + { + await (await GetDbContextAsync()).Set().Where(x => x.RoleId == sourceRoleId).ExecuteDeleteAsync(GetCancellationToken(cancellationToken)); + } + } + + public virtual async Task UpdateOrganizationAsync(Guid sourceOrganizationId, Guid? targetOrganizationId, CancellationToken cancellationToken = default) + { + if (targetOrganizationId != null) + { + var users = await (await GetDbContextAsync()).Set().Where(x => x.OrganizationUnitId == targetOrganizationId).Select(x => x.UserId).ToArrayAsync(cancellationToken: cancellationToken); + await (await GetDbContextAsync()).Set().Where(x => x.OrganizationUnitId == sourceOrganizationId && !users.Contains(x.UserId)).ExecuteUpdateAsync(t => t.SetProperty(e => e.OrganizationUnitId, targetOrganizationId), GetCancellationToken(cancellationToken)); + await (await GetDbContextAsync()).Set().Where(x => x.OrganizationUnitId == sourceOrganizationId).ExecuteDeleteAsync(GetCancellationToken(cancellationToken)); + } + else + { + await (await GetDbContextAsync()).Set().Where(x => x.OrganizationUnitId == sourceOrganizationId).ExecuteDeleteAsync(GetCancellationToken(cancellationToken)); + } + } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs index 552e22afbe..b37112c317 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs @@ -324,4 +324,40 @@ public class MongoIdentityUserRepository : MongoDbRepository ids.Contains(x.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); } + + public virtual async Task UpdateRoleAsync(Guid sourceRoleId, Guid? targetRoleId, CancellationToken cancellationToken = default) + { + var users = await (await GetMongoQueryableAsync(cancellationToken)) + .Where(x => x.Roles.Any(r => r.RoleId == sourceRoleId)) + .ToListAsync(GetCancellationToken(cancellationToken)); + + foreach (var user in users) + { + user.RemoveRole(sourceRoleId); + if (targetRoleId.HasValue) + { + user.AddRole(targetRoleId.Value); + } + } + + await UpdateManyAsync(users, cancellationToken: cancellationToken); + } + + public virtual async Task UpdateOrganizationAsync(Guid sourceOrganizationId, Guid? targetOrganizationId, CancellationToken cancellationToken = default) + { + var users = await (await GetMongoQueryableAsync(cancellationToken)) + .Where(x => x.OrganizationUnits.Any(r => r.OrganizationUnitId == sourceOrganizationId)) + .ToListAsync(GetCancellationToken(cancellationToken)); + + foreach (var user in users) + { + user.RemoveOrganizationUnit(sourceOrganizationId); + if (targetOrganizationId.HasValue) + { + user.AddOrganizationUnit(targetOrganizationId.Value); + } + } + + await UpdateManyAsync(users, cancellationToken: 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 dc2b28690a..dbd2e89fbf 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 @@ -147,6 +147,7 @@ public class AbpIdentityTestDataBuilder : ITransientDependency var bob = new IdentityUser(_testData.UserBobId, "bob", "bob@abp.io"); bob.SetIsActive(false); + bob.AddRole(_managerRole.Id); await _userManager.CreateAsync(bob, "1q2w3E*"); } @@ -205,24 +206,24 @@ public class AbpIdentityTestDataBuilder : ITransientDependency private async Task AddUserDelegations() { await _identityUserDelegationRepository.InsertAsync( - new IdentityUserDelegation(_guidGenerator.Create(), + new IdentityUserDelegation(_guidGenerator.Create(), _testData.UserJohnId, - _testData.UserDavidId, - DateTime.Now.AddDays(-2), + _testData.UserDavidId, + DateTime.Now.AddDays(-2), DateTime.Now.AddDays(-1))); - + await _identityUserDelegationRepository.InsertAsync( - new IdentityUserDelegation(_guidGenerator.Create(), + new IdentityUserDelegation(_guidGenerator.Create(), _testData.UserJohnId, - _testData.UserDavidId, - DateTime.Now.AddDays(-1), + _testData.UserDavidId, + DateTime.Now.AddDays(-1), DateTime.Now.AddDays(1))); - + await _identityUserDelegationRepository.InsertAsync( - new IdentityUserDelegation(_guidGenerator.Create(), + new IdentityUserDelegation(_guidGenerator.Create(), _testData.UserNeoId, - _testData.UserDavidId, - DateTime.Now.AddDays(-1), + _testData.UserDavidId, + DateTime.Now.AddDays(-1), DateTime.Now.AddDays(1))); } } diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserRepository_Tests.cs index 3931ecbafe..cb08fad60d 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserRepository_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserRepository_Tests.cs @@ -16,12 +16,16 @@ public abstract class IdentityUserRepository_Tests : AbpIdentity protected IIdentityUserRepository UserRepository { get; } protected ILookupNormalizer LookupNormalizer { get; } protected IOrganizationUnitRepository OrganizationUnitRepository { get; } + protected OrganizationUnitManager OrganizationUnitManager { get; } + protected IdentityTestData TestData { get; } protected IdentityUserRepository_Tests() { - UserRepository = ServiceProvider.GetRequiredService(); - LookupNormalizer = ServiceProvider.GetRequiredService(); - OrganizationUnitRepository = ServiceProvider.GetRequiredService(); + UserRepository = GetRequiredService(); + LookupNormalizer = GetRequiredService(); + OrganizationUnitRepository = GetRequiredService(); + OrganizationUnitManager = GetRequiredService();; + TestData = ServiceProvider.GetRequiredService(); } [Fact] @@ -175,4 +179,69 @@ public abstract class IdentityUserRepository_Tests : AbpIdentity organizationUnit.ShouldNotBeNull(); return organizationUnit; } + + [Fact] + public async Task UpdateRolesAsync() + { + var john = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash")); + var roles = await UserRepository.GetRolesAsync(john.Id); + roles.Count.ShouldBe(3); + roles.ShouldContain(r => r.Name == "moderator"); + roles.ShouldContain(r => r.Name == "supporter"); + roles.ShouldContain(r => r.Name == "manager"); + + var supporter = roles.First(x => x.NormalizedName == LookupNormalizer.NormalizeName("supporter")); + var manager = roles.First(x => x.NormalizedName == LookupNormalizer.NormalizeName("manager")); + + await UserRepository.UpdateRoleAsync(supporter.Id, null); + + roles = await UserRepository.GetRolesAsync(john.Id); + roles.Count.ShouldBe(2); + roles.ShouldContain(r => r.Name == "moderator"); + roles.ShouldContain(r => r.Name == "manager"); + + var bob = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("bob")); + roles = await UserRepository.GetRolesAsync(bob.Id); + roles.Count.ShouldBe(1); + roles.ShouldContain(r => r.Name == "manager"); + + await UserRepository.UpdateRoleAsync(manager.Id, supporter.Id); + + roles = await UserRepository.GetRolesAsync(bob.Id); + roles.Count.ShouldBe(1); + roles.ShouldContain(r => r.Name == "supporter"); + } + + [Fact] + public async Task UpdateOrganizationAsync() + { + var david = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("david")); + var organizationUnits = await UserRepository.GetOrganizationUnitsAsync(david.Id); + + var ou111 = await OrganizationUnitRepository.GetAsync("OU111"); + var ou112 = await OrganizationUnitRepository.GetAsync("OU112"); + + organizationUnits.Count.ShouldBe(1); + organizationUnits.ShouldContain(r => r.Id == ou112.Id); + + await UserRepository.UpdateOrganizationAsync(ou112.Id, null); + + organizationUnits = await UserRepository.GetOrganizationUnitsAsync(david.Id); + organizationUnits.Count.ShouldBe(0); + + var ou111Users = await UserRepository.GetUsersInOrganizationUnitAsync(ou111.Id); + ou111Users.Count.ShouldBe(2); + ou111Users.ShouldContain(x => x.UserName == "john.nash"); + ou111Users.ShouldContain(x => x.UserName == "neo"); + + var ou112Users = await UserRepository.GetUsersInOrganizationUnitAsync(ou112.Id); + ou112Users.Count.ShouldBe(0); + + await UserRepository.UpdateOrganizationAsync(ou111.Id, ou112.Id); + + ou112Users = await UserRepository.GetUsersInOrganizationUnitAsync(ou112.Id); + ou112Users.Count.ShouldBe(2); + ou112Users.ShouldContain(x => x.UserName == "john.nash"); + ou112Users.ShouldContain(x => x.UserName == "neo"); + } }