diff --git a/AsbCloudApp/Comparators/ComparerIId.cs b/AsbCloudApp/Comparators/ComparerIId.cs new file mode 100644 index 00000000..a43ff8fd --- /dev/null +++ b/AsbCloudApp/Comparators/ComparerIId.cs @@ -0,0 +1,24 @@ +using AsbCloudApp.Data; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace AsbCloudApp.Comparators +{ + public class ComparerIId : IComparer, IEqualityComparer + { + private static readonly ComparerIId instance = new ComparerIId(); + private ComparerIId(){} + + public static ComparerIId GetInstance() => instance; + + public int Compare(IId x, IId y) => + x.Id.CompareTo(y.Id); + + public bool Equals(IId x, IId y) => + x.Id == y.Id; + + public int GetHashCode([DisallowNull] IId obj) => + obj.GetHashCode(); + + } +} diff --git a/AsbCloudApp/Services/IUserRoleService.cs b/AsbCloudApp/Services/IUserRoleService.cs index d651c189..3d5a7ec3 100644 --- a/AsbCloudApp/Services/IUserRoleService.cs +++ b/AsbCloudApp/Services/IUserRoleService.cs @@ -9,7 +9,7 @@ namespace AsbCloudApp.Services { Task GetByNameAsync(string name, CancellationToken token = default); Task> GetByNamesAsync(IEnumerable names, CancellationToken token = default); - List GetNestedById(int id, int counter = 10); + IEnumerable GetNestedById(int id, int counter = 10); bool HasPermission(IEnumerable rolesIds, string permissionName); } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/UserRoleService.cs b/AsbCloudInfrastructure/Services/UserRoleService.cs index c4946ed0..221b70f7 100644 --- a/AsbCloudInfrastructure/Services/UserRoleService.cs +++ b/AsbCloudInfrastructure/Services/UserRoleService.cs @@ -8,6 +8,7 @@ using AsbCloudInfrastructure.Services.Cache; using Mapster; using AsbCloudApp.Services; using System; +using AsbCloudApp.Comparators; namespace AsbCloudInfrastructure.Services { @@ -20,7 +21,7 @@ namespace AsbCloudInfrastructure.Services public UserRoleService(IAsbCloudDbContext context, CacheDb cacheDb) { - cacheUserRoles = cacheDb.GetCachedTable((AsbCloudDbContext)context, nameof(UserRole.RelationUserRolePermissions)); + cacheUserRoles = cacheDb.GetCachedTable((AsbCloudDbContext)context, nameof(UserRole.RelationUserRolePermissions), nameof(UserRole.RelationUserRoleUserRoles)); cacheUserRolePermissions = cacheDb.GetCachedTable((AsbCloudDbContext)context, nameof(RelationUserRolePermission.Permission)); } @@ -106,18 +107,26 @@ namespace AsbCloudInfrastructure.Services return dto.Id; } - public List GetNestedById(int id, int recursionLevel = 7) + public IEnumerable GetNestedById(int id, int recursionLevel = 7) { var role = cacheUserRoles.FirstOrDefault(r => r.Id == id); if (role is null) return null; var dto = Convert(role); - if (role.IdParent is null || recursionLevel == 0) - return new List { dto }; - var parentRoles = GetNestedById((int)role.IdParent, --recursionLevel) ?? - new List(); - parentRoles.Add(dto); - return parentRoles; + var roles = new SortedSet(ComparerIId.GetInstance()) { dto }; + + if (recursionLevel <= 0 || role.RelationUserRoleUserRoles?.Any() != true) + return roles; + + foreach (var relation in role.RelationUserRoleUserRoles) + { + var nestedRoles = GetNestedById(relation.IdInclude, --recursionLevel); + if (nestedRoles?.Any() != true) + continue; + foreach (var nestedRole in nestedRoles) + roles.Add(nestedRole); + } + return roles; } private async Task UpdatePermissionsAsync(UserRoleDto roleDto, CancellationToken token) @@ -168,10 +177,15 @@ namespace AsbCloudInfrastructure.Services { if (userRole.RelationUserRolePermissions.Any(p => p.IdPermission == idPermission)) return true; - if (userRole.IdParent is not null && recursionLevel > 0) + + if (recursionLevel <= 0 || userRole.RelationUserRoleUserRoles?.Any() != true) + return false; + + foreach (var relation in userRole.RelationUserRoleUserRoles) { - var parentRole = cacheUserRoles.FirstOrDefault(p => p.Id == userRole.IdParent); - return HasPermission(parentRole, idPermission, --recursionLevel); + var includedRole = cacheUserRoles.First(p => p.Id == relation.IdInclude); + if (HasPermission(includedRole, idPermission, --recursionLevel)) + return true; } return false; } diff --git a/AsbCloudWebApi.Tests/ServicesTests/UserRoleServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/UserRoleServiceTest.cs new file mode 100644 index 00000000..8c70fc22 --- /dev/null +++ b/AsbCloudWebApi.Tests/ServicesTests/UserRoleServiceTest.cs @@ -0,0 +1,94 @@ +using AsbCloudDb.Model; +using AsbCloudInfrastructure.Services; +using AsbCloudInfrastructure.Services.Cache; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace AsbCloudWebApi.Tests.ServicesTests +{ + public class UserRoleServiceTest + { + private readonly AsbCloudDbContext context; + private readonly CacheDb cacheDb; + + private readonly List roles = new() { + new UserRole { Id = 1_000_001, Caption = "role 1 level 0" }, + new UserRole { Id = 1_000_002, Caption = "role 2 level 1" }, + new UserRole { Id = 1_000_003, Caption = "role 3 level 1" }, + new UserRole { Id = 1_000_004, Caption = "role 4 level 2" }, + }; + + private readonly List relationRoleRole = new() + { + new RelationUserRoleUserRole { Id = 1_000_002, IdInclude = 1_000_001 }, + new RelationUserRoleUserRole { Id = 1_000_003, IdInclude = 1_000_001 }, + new RelationUserRoleUserRole { Id = 1_000_004, IdInclude = 1_000_002 }, + new RelationUserRoleUserRole { Id = 1_000_004, IdInclude = 1_000_003 }, + }; + + private readonly List permissions = new() + { + new Permission { Id = 2_000_001, Name = "permission 1" }, + new Permission { Id = 2_000_002, Name = "permission 2" }, + new Permission { Id = 2_000_003, Name = "permission 3" }, + new Permission { Id = 2_000_004, Name = "permission 4" }, + }; + + private readonly List relationRolePermission = new() + { + new RelationUserRolePermission { IdUserRole = 1_000_001, IdPermission = 2_000_001 }, + new RelationUserRolePermission { IdUserRole = 1_000_002, IdPermission = 2_000_002 }, + new RelationUserRolePermission { IdUserRole = 1_000_003, IdPermission = 2_000_003 }, + new RelationUserRolePermission { IdUserRole = 1_000_004, IdPermission = 2_000_004 }, + }; + + public UserRoleServiceTest() + { + cacheDb = new CacheDb(); + context = TestHelpter.MakeTestContext(); + context.UserRoles.RemoveRange(roles); + context.Permissions.RemoveRange(permissions); + context.SaveChanges(); + context.UserRoles.AddRange(roles); + context.Permissions.AddRange(permissions); + context.SaveChanges(); + context.RelationUserRoleUserRoles.AddRange(relationRoleRole); + context.RelationUserRolePermissions.AddRange(relationRolePermission); + context.SaveChanges(); + } + + ~UserRoleServiceTest(){ + context.UserRoles.RemoveRange(roles); + context.Permissions.RemoveRange(permissions); + context.RelationUserRoleUserRoles.RemoveRange(relationRoleRole); + context.RelationUserRolePermissions.RemoveRange(relationRolePermission); + context.SaveChanges(); + context.Dispose(); + } + + [Fact] + public void GetNestedById_return_4_items() + { + var service = new UserRoleService(context, cacheDb); + var nestedRoles = service.GetNestedById(1_000_004); + Assert.Equal(roles.Count, nestedRoles.Count()); + } + + [Fact] + public void HasPermission_return_true() + { + var service = new UserRoleService(context, cacheDb); + var result = service.HasPermission(new int[] { 1_000_004 }, "permission 1"); + Assert.True(result); + } + + [Fact] + public void HasPermission_return_false() + { + var service = new UserRoleService(context, cacheDb); + var result = service.HasPermission(new int[] { 1_000_003 }, "permission 2"); + Assert.False(result); + } + } +} diff --git a/ConsoleAppDbExperiments/ConsoleAppDbExperiments.csproj b/ConsoleAppDbExperiments/ConsoleAppDbExperiments.csproj deleted file mode 100644 index 1ce91968..00000000 --- a/ConsoleAppDbExperiments/ConsoleAppDbExperiments.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - Exe - net6.0 - enable - enable - - - - - - - - diff --git a/ConsoleAppDbExperiments/Program.cs b/ConsoleAppDbExperiments/Program.cs deleted file mode 100644 index 82932781..00000000 --- a/ConsoleAppDbExperiments/Program.cs +++ /dev/null @@ -1,47 +0,0 @@ -using AsbCloudApp.Data; -using AsbCloudDb.Model; -using Microsoft.EntityFrameworkCore; - -var options = new DbContextOptionsBuilder() - .UseNpgsql("Host=localhost;Database=experiments;Username=postgres;Password=q;Persist Security Info=True;Include Error Detail=True") - .Options; -var context = new AsbCloudDbContext(options); - -var rels = context.RelationUserRoleUserRoles.Include(r=>r.Role).Include(r => r.IncludeRole); - -IEnumerable GetIncludedRole(int id) -{ - var res = context.UserRoles - .Include(r=>r.RelationUserRoleUserRoles) - .Where(r=>r.Id == id) - .SelectMany(r=>r.); - return rels.Where(r => r.Id == id).; -} - -UserRoleDto Convert(UserRole role) -{ - if (role is null) - return null; - - var res = new UserRoleDto - { - Id = role.Id, - Caption = role.Caption, - IdType = role.IdType, - Permissions = role.RelationUserRolePermissions?.Select(r => r.Permission).ToList(), - }; -} - -PermissionDto Convert(Permission permission) -{ - if (permission is null) - return null; - return new PermissionDto - { - Name = permission.Name, - Id = permission.Id, - Description = permission.Description - }; -} - -Console.WriteLine("Hello, World!");