diff --git a/AsbCloudApp/Repositories/IUserRepository.cs b/AsbCloudApp/Repositories/IUserRepository.cs
new file mode 100644
index 00000000..02b713fe
--- /dev/null
+++ b/AsbCloudApp/Repositories/IUserRepository.cs
@@ -0,0 +1,41 @@
+using AsbCloudApp.Data;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace AsbCloudApp.Repositories
+{
+ ///
+ /// Репозиторий пользователей
+ ///
+ public interface IUserRepository
+ {
+ ///
+ /// Добавление пользователя
+ ///
+ ///
+ ///
+ ///
+ Task InsertAsync(UserExtendedDto dto, CancellationToken token);
+
+ ///
+ /// Обновление ролей пользователя
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task UpdateRolesCacheForUserAsync(int idUser, IEnumerable newRoles, CancellationToken token);
+
+ ///
+ /// Получить пользователя по логину
+ ///
+ ///
+ ///
+ ///
+ Task GetUserByLoginAsync(string login, CancellationToken token);
+ }
+}
diff --git a/AsbCloudApp/Services/IUserRoleService.cs b/AsbCloudApp/Repositories/IUserRoleRepository.cs
similarity index 70%
rename from AsbCloudApp/Services/IUserRoleService.cs
rename to AsbCloudApp/Repositories/IUserRoleRepository.cs
index b9341c9d..177e4379 100644
--- a/AsbCloudApp/Services/IUserRoleService.cs
+++ b/AsbCloudApp/Repositories/IUserRoleRepository.cs
@@ -1,23 +1,24 @@
using AsbCloudApp.Data;
+using AsbCloudApp.Services;
using System.Collections.Generic;
-using System.Threading;
using System.Threading.Tasks;
+using System.Threading;
-namespace AsbCloudApp.Services
+namespace AsbCloudApp.Repositories
{
+#nullable enable
///
- /// Репозиторий ролей пользователя
+ /// Разрешения на доступ к данным
///
- public interface IUserRoleService : ICrudService
+ public interface IUserRoleRepository : ICrudService
{
- // todo: переименовать
///
/// получить dto по названиям
///
///
///
///
- Task> GetByNamesAsync(IEnumerable names, CancellationToken token = default);
+ Task?> GetByNamesAsync(IEnumerable names, CancellationToken token = default);
///
/// получить все вложенные разрешения
@@ -25,7 +26,7 @@ namespace AsbCloudApp.Services
///
///
///
- IEnumerable GetNestedById(int id, int counter = 10);
+ IEnumerable? GetNestedById(int id, int counter = 10);
///
/// определяет содержится ли разрешение в одной из указанных ролей
@@ -35,4 +36,5 @@ namespace AsbCloudApp.Services
///
bool HasPermission(IEnumerable rolesIds, string permissionName);
}
-}
\ No newline at end of file
+#nullable disable
+}
diff --git a/AsbCloudApp/Services/IUserService.cs b/AsbCloudApp/Services/IUserService.cs
index 34f12212..5eb9ab70 100644
--- a/AsbCloudApp/Services/IUserService.cs
+++ b/AsbCloudApp/Services/IUserService.cs
@@ -1,4 +1,5 @@
using AsbCloudApp.Data;
+using AsbCloudApp.Repositories;
using System.Collections.Generic;
namespace AsbCloudApp.Services
@@ -11,7 +12,7 @@ namespace AsbCloudApp.Services
///
/// Сервис ролей
///
- IUserRoleService RoleService { get; }
+ IUserRoleRepository RoleService { get; }
///
/// Получить список всех прав пользователя (включая наследование групп)
diff --git a/AsbCloudApp/Services/IWellFinalDocumentsService.cs b/AsbCloudApp/Services/IWellFinalDocumentsService.cs
index 7b910c74..4da098ce 100644
--- a/AsbCloudApp/Services/IWellFinalDocumentsService.cs
+++ b/AsbCloudApp/Services/IWellFinalDocumentsService.cs
@@ -50,7 +50,8 @@ namespace AsbCloudApp.Services
///
/// Сохранение файла
///
- ///
+ ///
+ ///
///
///
///
diff --git a/AsbCloudDb/Model/IAsbCloudDbContext.cs b/AsbCloudDb/Model/IAsbCloudDbContext.cs
index 42642377..5bab3c21 100644
--- a/AsbCloudDb/Model/IAsbCloudDbContext.cs
+++ b/AsbCloudDb/Model/IAsbCloudDbContext.cs
@@ -28,6 +28,7 @@ namespace AsbCloudDb.Model
DbSet RelationDrillingProgramPartUsers { get; }
DbSet RelationUserRolePermissions { get; }
DbSet RelationUserUserRoles { get; }
+ DbSet RelationUserRoleUserRoles { get; }
DbSet ReportProperties { get; }
DbSet Subsystems { get; }
DbSet SubsystemOperationTimes { get; }
diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs
index 48d759fc..cc6c279a 100644
--- a/AsbCloudInfrastructure/DependencyInjection.cs
+++ b/AsbCloudInfrastructure/DependencyInjection.cs
@@ -121,15 +121,12 @@ namespace AsbCloudInfrastructure
services.AddTransient();
services.AddTransient();
services.AddTransient();
- services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient();
- //services.AddTransient();
-
services.AddTransient();
services.AddTransient();
services.AddTransient, CrudWellRelatedServiceBase>();
@@ -165,6 +162,7 @@ namespace AsbCloudInfrastructure
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
// Subsystem service
services.AddTransient, CrudCacheServiceBase>();
services.AddTransient();
diff --git a/AsbCloudInfrastructure/Repository/UserRepository.cs b/AsbCloudInfrastructure/Repository/UserRepository.cs
new file mode 100644
index 00000000..83c058f9
--- /dev/null
+++ b/AsbCloudInfrastructure/Repository/UserRepository.cs
@@ -0,0 +1,102 @@
+using AsbCloudApp.Data;
+using AsbCloudApp.Repositories;
+using AsbCloudDb.Model;
+using AsbCloudInfrastructure.EfCache;
+using Mapster;
+using Microsoft.EntityFrameworkCore;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace AsbCloudInfrastructure.Repository
+{
+#nullable enable
+ public class UserRepository : IUserRepository
+ {
+ private readonly IAsbCloudDbContext db;
+ private static readonly System.TimeSpan cacheObsolescence = System.TimeSpan.FromMinutes(15);
+ private static readonly TypeAdapterConfig userTypeAdapterConfig = TypeAdapterConfig
+ .NewConfig()
+ .Ignore(dst => dst.Company,
+ dst => dst.FileMarks,
+ dst => dst.Files,
+ dst => dst.RelationUsersUserRoles)
+ .Config;
+
+ public UserRepository(IAsbCloudDbContext db) {
+ this.db = db;
+ }
+
+ public async Task InsertAsync(UserExtendedDto dto, CancellationToken token)
+ {
+ dto.Id = default;
+ var updatedEntity = await db.Users.AddAsync(Convert(dto), token).ConfigureAwait(false);
+ return Convert(updatedEntity.Entity);
+ }
+
+ public async Task UpdateRolesCacheForUserAsync(int idUser, IEnumerable newRoles, CancellationToken token)
+ {
+ var entity = await db.RelationUserUserRoles.FirstOrDefaultAsync(x => x.IdUser == idUser, token).ConfigureAwait(false);
+ if (entity is not null)
+ {
+ db.RelationUserUserRoles.Remove(entity);
+ if (newRoles?.Any() == true)
+ await db.RelationUserUserRoles.AddRangeAsync(newRoles.Select(role => new RelationUserUserRole
+ {
+ IdUser = idUser,
+ IdUserRole = role.Id
+ }), token).ConfigureAwait(false);
+ }
+ }
+
+ public async Task GetUserByLoginAsync(string login, CancellationToken token)
+ {
+ var entities = await db.Users.FromCacheAsync("Users", cacheObsolescence, token).ConfigureAwait(false);
+ var entity = entities.FirstOrDefault(x => x.Login.ToLower() == login.ToLower());
+ if (entity is not null)
+ return Convert(entity);
+ return null;
+ }
+
+ public async Task?> GetAllAsync(CancellationToken token = default)
+ {
+ var entities = await db.Users.FromCacheAsync("Users", cacheObsolescence, token).ConfigureAwait(false);
+ if (entities is null)
+ return null;
+ var dtos = entities.Select(Convert).ToList();
+ //for (var i = 0; i < dtos.Count; i++)
+ // dtos[i].RoleNames = GetRolesNamesByIdUser(dtos[i].Id, token);
+ return dtos;
+ }
+
+ //private async Task> GetRolesNamesByIdUser(int idUser, CancellationToken token)
+ //=> await GetRolesByIdUser(idUser, token)
+ // ?.Select(r => r.Caption)
+ // .Distinct();
+
+ //public async Task> GetRolesByIdUser(int idUser, CancellationToken token, int nestedLevel = 0)
+ //{
+ // var allRoles = await db.RelationUserUserRoles.FromCacheAsync("RelationUserUserRoles", cacheObsolescence, token).ConfigureAwait(false);
+ // var roles = allRoles.Where(r => r.IdUser == idUser);
+ // if (roles?.Any() != true)
+ // return null;
+ // return roles.SelectMany(r => RoleService.GetNestedById(r.IdUserRole, nestedLevel));
+ //}
+
+ private User Convert(UserExtendedDto dto)
+ {
+ var entity = dto.Adapt(userTypeAdapterConfig);
+ if (string.IsNullOrEmpty(entity.PasswordHash))
+ entity.PasswordHash = db.Users.FirstOrDefault(u => u.Id == dto.Id)?.PasswordHash;
+ return entity;
+ }
+
+ private UserExtendedDto Convert(User entity)
+ {
+ var dto = entity.Adapt();
+ return dto;
+ }
+ }
+#nullable disable
+}
diff --git a/AsbCloudInfrastructure/Repository/UserRoleRepository.cs b/AsbCloudInfrastructure/Repository/UserRoleRepository.cs
new file mode 100644
index 00000000..89d6150e
--- /dev/null
+++ b/AsbCloudInfrastructure/Repository/UserRoleRepository.cs
@@ -0,0 +1,311 @@
+using AsbCloudApp.Comparators;
+using AsbCloudApp.Data;
+using AsbCloudApp.Exceptions;
+using AsbCloudApp.Repositories;
+using AsbCloudDb;
+using AsbCloudDb.Model;
+using AsbCloudInfrastructure.EfCache;
+using Mapster;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace AsbCloudInfrastructure.Repository
+{
+#nullable enable
+ public class UserRoleRepository : IUserRoleRepository
+ {
+ private readonly IAsbCloudDbContext dbContext;
+ private const string userRoleCacheTag = "UserRole";
+ private const string relationUserRoleUserRoleCacheTag = "RelationUserRoleUserRole";
+ private const string relationUserRolePermissionsCacheTag = "RelationUserRolePermissions";
+ private static readonly TimeSpan relationCacheObsolence = TimeSpan.FromMinutes(15);
+
+ public UserRoleRepository(IAsbCloudDbContext dbContext)
+ {
+ this.dbContext = dbContext;
+ }
+
+ public async Task InsertAsync(UserRoleDto dto, CancellationToken token)
+ {
+ var entity = dto.Adapt();
+ var updatedEntity = await dbContext.UserRoles.AddAsync(entity, token)
+ .ConfigureAwait(false);
+ dto.Id = updatedEntity.Entity.Id;
+ await UpdatePermissionsAsync(dto, token);
+ await UpdateIncludedRolesAsync(dto, token);
+
+ dbContext.UserRoles.DropCache();
+ return updatedEntity?.Entity?.Id ?? 0;
+ }
+
+ public Task InsertRangeAsync(IEnumerable newItems, CancellationToken token)
+ {
+ throw new NotImplementedException();
+ }
+
+ public async Task> GetAllAsync(CancellationToken token)
+ {
+ var entities = await GetCacheUserRoleAsync(token)
+ .ConfigureAwait(false);
+
+ if (entities is not null)
+ {
+ var dtos = entities.Select(Convert);
+ return dtos;
+ }
+ else
+ return new List();
+ }
+
+ public UserRoleDto? GetOrDefault(int id)
+ {
+ var entity = GetCacheUserRole().FirstOrDefault(x => x.Id == id);
+ if (entity is null)
+ return null;
+ var dto = Convert(entity);
+ return dto;
+ }
+
+ public async Task GetOrDefaultAsync(int id, CancellationToken token)
+ {
+ var entity = (await GetCacheUserRoleAsync(token)
+ .ConfigureAwait(false)).FirstOrDefault(r => r.Id == id);
+ if (entity is null)
+ return null;
+ var dto = Convert(entity);
+ return dto;
+ }
+
+ public async Task?> GetByNamesAsync(IEnumerable names, CancellationToken token)
+ {
+ if (names?.Any() != true)
+ return null;
+ var entities = (await GetCacheUserRoleAsync(token)).Where(r => names.Contains(r.Caption));
+ if (entities?.Count() != names.Count())
+ throw new ArgumentInvalidException("Invalid role names", nameof(names));
+ var dtos = entities.Select(Convert);
+ return dtos;
+ }
+
+ public async Task UpdateAsync(UserRoleDto dto, CancellationToken token)
+ {
+ var entity = Convert(dto);
+ await UpdatePermissionsAsync(dto, token);
+ await UpdateIncludedRolesAsync(dto, token);
+
+ var result = dbContext.UserRoles.Upsert(entity);
+ DropCacheUserRole();
+ return result?.Entity?.Id ?? 0;
+ }
+
+ public IEnumerable? GetNestedById(int id, int recursionLevel = 7)
+ {
+ var role = GetCacheUserRole().FirstOrDefault(r => r.Id == id);
+ if (role is null)
+ return null;
+ var dto = Convert(role);
+ 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;
+ }
+
+ public async Task DeleteAsync(int id, CancellationToken token)
+ {
+ var entity = (await GetCacheUserRoleAsync(token)).FirstOrDefault(r => r.Id == id);
+
+ if (entity is not null)
+ {
+ var removeEntity = dbContext.UserRoles.Remove(entity);
+ await dbContext.SaveChangesAsync(token);
+ DropCacheUserRole();
+ return removeEntity?.Entity?.Id ?? 0;
+ }
+ else return 0;
+ }
+
+ public async Task DeleteAsync(IEnumerable ids, CancellationToken token)
+ {
+ var entities = (await GetCacheUserRoleAsync(token)).Where(r => ids.Contains(r.Id));
+
+ if (entities is not null)
+ {
+ var count = entities.Count();
+ dbContext.UserRoles.RemoveRange(entities);
+ await dbContext.SaveChangesAsync(token);
+ DropCacheUserRole();
+ return count;
+ }
+ else return 0;
+ }
+
+ public bool HasPermission(IEnumerable rolesIds, string permissionName)
+ {
+ var permissionInfo = GetCacheRelationUserRolePermissions()
+ .FirstOrDefault(p => p. Permission?.Name.ToLower() == permissionName.ToLower())
+ ?.Permission;
+
+ if (permissionInfo is null)
+ return false;
+
+ if (rolesIds.Contains(1))
+ return true;
+
+ var idPermissionInfo = permissionInfo.Id;
+ var roles = GetCacheUserRole()
+ .Where(r => rolesIds.Contains(r.Id));
+ foreach (var role in roles)
+ if (HasPermission(role, idPermissionInfo))
+ return true;
+ return false;
+ }
+
+ private bool HasPermission(UserRole userRole, int idPermission, int recursionLevel = 7)
+ {
+ if (userRole.RelationUserRolePermissions.Any(p => p.IdPermission == idPermission))
+ return true;
+
+ if (recursionLevel <= 0 || userRole.RelationUserRoleUserRoles?.Any() != true)
+ return false;
+
+ foreach (var relation in userRole.RelationUserRoleUserRoles)
+ {
+ var includedRole = GetCacheUserRole()
+ .First(p => p.Id == relation.IdInclude);
+ if (HasPermission(includedRole, idPermission, --recursionLevel))
+ return true;
+ }
+ return false;
+ }
+
+ private async Task UpdateIncludedRolesAsync(UserRoleDto dto, CancellationToken token)
+ {
+ if (dto?.Roles is null)
+ return;
+
+ var relations = (await GetCacheRelationUserRoleUserRoleAsync(token).ConfigureAwait(false))
+ .Where(r => r.Id == dto.Id);
+
+ dbContext.RelationUserRoleUserRoles.RemoveRange(relations);
+
+ if (dto.Roles.Any())
+ {
+ var newRelations = dto.Roles.Select(r => new RelationUserRoleUserRole { Id = dto.Id, IdInclude = r.Id });
+ await dbContext.RelationUserRoleUserRoles.AddRangeAsync(newRelations, token);
+ await dbContext.SaveChangesAsync(token);
+ DropCacheRelationUserRoleUserRole();
+ }
+ }
+
+ private async Task UpdatePermissionsAsync(UserRoleDto dto, CancellationToken token)
+ {
+ if (dto?.Permissions is null)
+ return;
+
+ var relations = (await GetCacheRelationUserRolePermissionsAsync(token).ConfigureAwait(false))
+ .Where(r => r.IdUserRole == dto.Id);
+
+ dbContext.RelationUserRolePermissions.RemoveRange(relations);
+
+ if (dto.Permissions.Any())
+ {
+ var newRelations = dto.Permissions.Select(p => new RelationUserRolePermission
+ {
+ IdPermission = p.Id,
+ IdUserRole = dto.Id,
+ });
+
+ await dbContext.RelationUserRolePermissions.AddRangeAsync(newRelations, token);
+ await dbContext.SaveChangesAsync(token);
+ DropCacheRelationCompanyWell();
+ }
+ }
+
+ private Task> GetCacheUserRoleAsync(CancellationToken token)
+ => dbContext.UserRoles
+ .Include(r => r.RelationUserRolePermissions)
+ .Include(r => r.RelationUserRoleUserRoles)
+ .FromCacheAsync(userRoleCacheTag, relationCacheObsolence, token);
+ private IEnumerable GetCacheUserRole()
+ => dbContext.UserRoles
+ .Include(r => r.RelationUserRolePermissions)
+ .Include(r => r.RelationUserRoleUserRoles)
+ .FromCache(userRoleCacheTag, relationCacheObsolence);
+ private void DropCacheUserRole()
+ => dbContext.RelationUserUserRoles.DropCache(relationUserRoleUserRoleCacheTag);
+
+ private Task> GetCacheRelationUserRoleUserRoleAsync(CancellationToken token)
+ => dbContext.RelationUserRoleUserRoles
+ .Include(r => r.IncludeRole)
+ .Include(r => r.Role)
+ .FromCacheAsync(relationUserRoleUserRoleCacheTag, relationCacheObsolence, token);
+ private IEnumerable GetCacheRelationUserRoleUserRole()
+ => dbContext.RelationUserRoleUserRoles
+ .Include(r => r.IncludeRole)
+ .Include(r => r.Role)
+ .FromCache(relationUserRoleUserRoleCacheTag, relationCacheObsolence);
+ private void DropCacheRelationUserRoleUserRole()
+ => dbContext.RelationUserUserRoles.DropCache(relationUserRoleUserRoleCacheTag);
+
+ private Task> GetCacheRelationUserRolePermissionsAsync(CancellationToken token)
+ => dbContext.RelationUserRolePermissions
+ .Include(r => r.UserRole)
+ .Include(r => r.Permission)
+ .FromCacheAsync(relationUserRolePermissionsCacheTag, relationCacheObsolence, token);
+ private IEnumerable GetCacheRelationUserRolePermissions()
+ => dbContext.RelationUserRolePermissions
+ .Include(r => r.UserRole)
+ .Include(r => r.Permission)
+ .FromCache(relationUserRolePermissionsCacheTag, relationCacheObsolence);
+ private void DropCacheRelationCompanyWell()
+ => dbContext.RelationUserRolePermissions.DropCache(relationUserRolePermissionsCacheTag);
+
+ private UserRoleDto Convert(UserRole entity)
+ {
+ var dto = entity.Adapt();
+ if (entity.RelationUserRolePermissions?.Any() == true)
+ {
+ dto.Permissions = GetCacheRelationUserRolePermissions()
+ .Where(r => entity.Id == r.IdUserRole)
+ .Select(r => Convert(r.Permission));
+ }
+
+ if (entity.RelationUserRoleUserRoles?.Any() == true)
+ {
+ dto.Roles = entity.RelationUserRoleUserRoles.Select(rel =>
+ {
+ var includedRole = GetCacheUserRole().First(r => r.Id == rel.IdInclude);
+ return Convert(includedRole);
+ }).ToList();
+ }
+ return dto;
+ }
+
+ private static PermissionDto Convert(Permission entity)
+ {
+ var dto = entity.Adapt();
+ return dto;
+ }
+
+ private static UserRole Convert(UserRoleDto dto)
+ {
+ var entity = dto.Adapt();
+ return entity;
+ }
+ }
+#nullable disable
+}
diff --git a/AsbCloudInfrastructure/Services/UserRoleService.cs b/AsbCloudInfrastructure/Services/UserRoleService.cs
deleted file mode 100644
index 37f05d8c..00000000
--- a/AsbCloudInfrastructure/Services/UserRoleService.cs
+++ /dev/null
@@ -1,234 +0,0 @@
-using AsbCloudApp.Comparators;
-using AsbCloudApp.Data;
-using AsbCloudApp.Exceptions;
-using AsbCloudApp.Services;
-using AsbCloudDb.Model;
-using AsbCloudInfrastructure.Services.Cache;
-using Mapster;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace AsbCloudInfrastructure.Services
-{
- public class UserRoleService : IUserRoleService
- {
- private readonly CacheTable cacheUserRoles;
- private readonly CacheTable cacheRelationUserRolePermissions;
- private readonly CacheTable cacheRelationUserRoleUserRole;
-
- public ISet Includes { get; } = new SortedSet();
-
- public UserRoleService(IAsbCloudDbContext context, CacheDb cacheDb)
- {
- cacheUserRoles = cacheDb.GetCachedTable((AsbCloudDbContext)context, nameof(UserRole.RelationUserRolePermissions), nameof(UserRole.RelationUserRoleUserRoles));
- cacheRelationUserRolePermissions = cacheDb.GetCachedTable((AsbCloudDbContext)context, nameof(RelationUserRolePermission.Permission));
- cacheRelationUserRoleUserRole = cacheDb.GetCachedTable((AsbCloudDbContext)context, nameof(RelationUserRoleUserRole.IncludeRole), nameof(RelationUserRoleUserRole.Role));
- }
-
- public async Task InsertAsync(UserRoleDto dto, CancellationToken token = default)
- {
- var entity = dto.Adapt();
- var updatedEntity = await cacheUserRoles.InsertAsync(entity, token)
- .ConfigureAwait(false);
- dto.Id = updatedEntity.Id;
- await UpdatePermissionsAsync(dto, token);
- await UpdateIncludedRolesAsync(dto, token);
-
- await cacheUserRoles.RefreshAsync(true, token)
- .ConfigureAwait(false);
- return updatedEntity?.Id ?? 0;
- }
-
- public Task InsertRangeAsync(IEnumerable dtos, CancellationToken token = default)
- {
- throw new NotImplementedException();
- //var entities = dtos.Adapt();
- //return await cacheUserRoles.InsertAsync(entities, token).ConfigureAwait(false);
- }
-
- public async Task> GetAllAsync(CancellationToken token = default)
- {
- var entities = await cacheUserRoles.WhereAsync(token)
- .ConfigureAwait(false);
- var dtos = entities?.Select(Convert);
- return dtos;
- }
- public UserRoleDto GetOrDefault(int id)
- {
- var entity = cacheUserRoles.FirstOrDefault(r => r.Id == id);
- if (entity is null)
- return null;
- var dto = Convert(entity);
- return dto;
- }
-
- public async Task GetOrDefaultAsync(int id, CancellationToken token = default)
- {
- var entity = await cacheUserRoles.FirstOrDefaultAsync(r => r.Id == id, token)
- .ConfigureAwait(false);
- if (entity is null)
- return null;
- var dto = Convert(entity);
- return dto;
- }
-
- public async Task> GetByNamesAsync(IEnumerable names, CancellationToken token = default)
- {
- if (names?.Any() != true)
- return null;
- var entities = await cacheUserRoles.WhereAsync(r => names.Contains(r.Caption), token)
- .ConfigureAwait(false);
- if (entities?.Count() != names.Count())
- throw new ArgumentInvalidException("Invalid role names", nameof(names));
- var dtos = entities.Select(Convert);
- return dtos;
- }
-
- public async Task UpdateAsync(UserRoleDto dto, CancellationToken token = default)
- {
- var entity = Convert(dto);
- await UpdatePermissionsAsync(dto, token);
- await UpdateIncludedRolesAsync(dto, token);
-
- var result = await cacheUserRoles.UpsertAsync(entity, token)
- .ConfigureAwait(false);
- return result;
- }
-
- 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);
- 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 dto, CancellationToken token)
- {
- if (dto?.Permissions is null)
- return;
-
- await cacheRelationUserRolePermissions.RemoveAsync(r => r.IdUserRole == dto.Id, token)
- .ConfigureAwait(false);
-
- if (dto.Permissions.Any())
- {
- var newRelationRoleToPermission = dto.Permissions.Select(p => new RelationUserRolePermission
- {
- IdPermission = p.Id,
- IdUserRole = dto.Id,
- });
-
- await cacheRelationUserRolePermissions.InsertAsync(newRelationRoleToPermission, token)
- .ConfigureAwait(false);
- }
- }
-
- private async Task UpdateIncludedRolesAsync(UserRoleDto dto, CancellationToken token)
- {
- if (dto?.Roles is null)
- return;
-
- await cacheRelationUserRoleUserRole.RemoveAsync(rel => rel.Id == dto.Id, token);
-
- if (dto.Roles.Any())
- {
- var newRelations = dto.Roles.Select(r => new RelationUserRoleUserRole { Id = dto.Id, IdInclude = r.Id });
- await cacheRelationUserRoleUserRole.UpsertAsync(newRelations, token);
- }
- }
-
- public Task DeleteAsync(int id, CancellationToken token = default)
- => cacheUserRoles.RemoveAsync(r => r.Id == id, token);
-
- public Task DeleteAsync(IEnumerable ids, CancellationToken token = default)
- => cacheUserRoles.RemoveAsync(r => ids.Contains(r.Id), token);
-
- public bool HasPermission(IEnumerable rolesIds, string permissionName)
- {
- var permissionInfo = cacheRelationUserRolePermissions
- .FirstOrDefault(p => p.Permission?.Name.ToLower() == permissionName.ToLower())
- ?.Permission;
-
- if (permissionInfo is null)
- return false;
-
- if (rolesIds.Contains(1))
- return true;
-
- var idPermissionInfo = permissionInfo.Id;
- var roles = cacheUserRoles.Where(r => rolesIds.Contains(r.Id));
- foreach (var role in roles)
- if (HasPermission(role, idPermissionInfo))
- return true;
- return false;
- }
-
- private bool HasPermission(UserRole userRole, int idPermission, int recursionLevel = 7)
- {
- if (userRole.RelationUserRolePermissions.Any(p => p.IdPermission == idPermission))
- return true;
-
- if (recursionLevel <= 0 || userRole.RelationUserRoleUserRoles?.Any() != true)
- return false;
-
- foreach (var relation in userRole.RelationUserRoleUserRoles)
- {
- var includedRole = cacheUserRoles.First(p => p.Id == relation.IdInclude);
- if (HasPermission(includedRole, idPermission, --recursionLevel))
- return true;
- }
- return false;
- }
-
- private static UserRole Convert(UserRoleDto dto)
- {
- var entity = dto.Adapt();
- return entity;
- }
-
- private UserRoleDto Convert(UserRole entity)
- {
- var dto = entity.Adapt();
- if (entity.RelationUserRolePermissions?.Any() == true)
- {
- dto.Permissions = cacheRelationUserRolePermissions
- .Where(r => entity.Id == r.IdUserRole)
- .Select(r => Convert(r.Permission));
- }
-
- if (entity.RelationUserRoleUserRoles?.Any() == true)
- {
- dto.Roles = entity.RelationUserRoleUserRoles.Select(rel =>
- {
- var includedRole = cacheUserRoles.First(r => r.Id == rel.IdInclude);
- return Convert(includedRole);
- }).ToList();
- }
- return dto;
- }
-
- private static PermissionDto Convert(Permission entity)
- {
- var dto = entity.Adapt();
- return dto;
- }
- }
-}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/UserService.cs b/AsbCloudInfrastructure/Services/UserService.cs
index c282204e..09e284ae 100644
--- a/AsbCloudInfrastructure/Services/UserService.cs
+++ b/AsbCloudInfrastructure/Services/UserService.cs
@@ -1,5 +1,6 @@
using AsbCloudApp.Data;
using AsbCloudApp.Exceptions;
+using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
@@ -17,7 +18,7 @@ namespace AsbCloudInfrastructure.Services
private readonly CacheTable cacheUsers;
private readonly CacheTable cacheRelationUserToRoles;
public ISet Includes { get; } = new SortedSet();
- public IUserRoleService RoleService { get; }
+ public IUserRoleRepository RoleService { get; }
private static readonly TypeAdapterConfig userTypeAdapterConfig = TypeAdapterConfig
.NewConfig()
@@ -27,7 +28,7 @@ namespace AsbCloudInfrastructure.Services
dst => dst.RelationUsersUserRoles)
.Config;
- public UserService(IAsbCloudDbContext context, CacheDb cacheDb, IUserRoleService roleService)
+ public UserService(IAsbCloudDbContext context, CacheDb cacheDb, IUserRoleRepository roleService)
{
var db = (AsbCloudDbContext)context;
cacheUsers = cacheDb.GetCachedTable(
diff --git a/AsbCloudWebApi.Tests/ServicesTests/UserRoleServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/UserRoleServiceTest.cs
deleted file mode 100644
index 8ce1c1b3..00000000
--- a/AsbCloudWebApi.Tests/ServicesTests/UserRoleServiceTest.cs
+++ /dev/null
@@ -1,187 +0,0 @@
-using AsbCloudApp.Data;
-using AsbCloudDb.Model;
-using AsbCloudInfrastructure.Services;
-using AsbCloudInfrastructure.Services.Cache;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-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);
- }
-
- [Fact]
- public async Task InsertAsync_returns_id()
- {
- var service = new UserRoleService(context, cacheDb);
- var newRole = new UserRoleDto
- {
- Caption = "new role",
- IdType = 0,
- };
- var id = await service.InsertAsync(newRole, CancellationToken.None);
- Assert.NotEqual(0, id);
- }
-
- [Fact]
- public async Task InsertAsync_updates_relation_to_permission()
- {
- var service = new UserRoleService(context, cacheDb);
- var newRole = new UserRoleDto
- {
- Caption = "new role",
- IdType = 0,
- Permissions = new[] { new PermissionDto { Id = 2_000_001 } },
- };
- var id = await service.InsertAsync(newRole, CancellationToken.None);
- var entity = await service.GetOrDefaultAsync(id);
- Assert.Equal(newRole.Permissions.Count(), entity.Permissions.Count());
- }
-
- [Fact]
- public async Task InsertAsync_updates_relation_to_role()
- {
- var service = new UserRoleService(context, cacheDb);
- var newRole = new UserRoleDto
- {
- Caption = "new role",
- IdType = 0,
- Roles = new[] { new UserRoleDto { Id = 1_000_001 } }
- };
- var id = await service.InsertAsync(newRole, CancellationToken.None);
- var entity = await service.GetOrDefaultAsync(id);
- Assert.Equal(newRole.Roles.Count, entity.Roles.Count);
- }
-
- [Fact]
- public async Task UpdateAsync_returns_id()
- {
- var service = new UserRoleService(context, cacheDb);
- const int updateId = 1_000_002;
- var modRole = new UserRoleDto
- {
- Id = updateId,
- Caption = "role 2 level 1"
- };
- var id = await service.UpdateAsync(modRole, CancellationToken.None);
- Assert.Equal(updateId, id);
- }
-
- [Fact]
- public async Task UpdateAsync_updates_relation_to_permission()
- {
- var service = new UserRoleService(context, cacheDb);
- const int updateId = 1_000_002;
- var modRole = new UserRoleDto
- {
- Id = updateId,
- Caption = "role 2 level 1",
- Permissions = new[] { new PermissionDto { Id = 2_000_001 } },
- };
- var id = await service.UpdateAsync(modRole, CancellationToken.None);
- var entity = await service.GetOrDefaultAsync(id);
- Assert.Equal(modRole.Permissions.Count(), entity.Permissions.Count());
- }
-
- [Fact]
- public async Task UpdateAsync_updates_relation_to_role()
- {
- var service = new UserRoleService(context, cacheDb);
- const int updateId = 1_000_002;
- var modRole = new UserRoleDto
- {
- Id = updateId,
- Caption = "role 2 level 1",
- Roles = new[] { new UserRoleDto { Id = 1_000_001 } }
- };
- var id = await service.UpdateAsync(modRole, CancellationToken.None);
- var entity = await service.GetOrDefaultAsync(id);
- Assert.Equal(modRole.Roles.Count(), entity.Roles.Count());
- }
- }
-}
diff --git a/AsbCloudWebApi.Tests/ServicesTests/UserServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/UserServiceTest.cs
index 1e3d1b3f..bd47b853 100644
--- a/AsbCloudWebApi.Tests/ServicesTests/UserServiceTest.cs
+++ b/AsbCloudWebApi.Tests/ServicesTests/UserServiceTest.cs
@@ -1,4 +1,5 @@
using AsbCloudApp.Data;
+using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services;
@@ -16,13 +17,13 @@ namespace AsbCloudWebApi.Tests.ServicesTests
{
private readonly AsbCloudDbContext context;
private readonly CacheDb cacheDb;
- private readonly Mock roleService;
+ private readonly Mock roleRepository;
public UserServiceTest()
{
context = TestHelpter.MakeTestContext();
cacheDb = new CacheDb();
- roleService = new Mock();
+ roleRepository = new Mock();
context.Users.RemoveRange(context.Users.Where(u => u.Id > 1));
context.SaveChanges();
@@ -37,7 +38,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
[Fact]
public async Task InsertAsync_returns_id()
{
- var service = new UserService(context, cacheDb, roleService.Object);
+ var service = new UserService(context, cacheDb, roleRepository.Object);
var dto = new UserExtendedDto
{
Id = 0,
@@ -60,7 +61,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
[Fact]
public async Task InsertAsync_busy_login_throws_exceprion()
{
- var service = new UserService(context, cacheDb, roleService.Object);
+ var service = new UserService(context, cacheDb, roleRepository.Object);
var dto = new UserExtendedDto
{
Id = 5,
diff --git a/AsbCloudWebApi/Controllers/AdminUserRoleController.cs b/AsbCloudWebApi/Controllers/AdminUserRoleController.cs
index 5625f0ae..d3ca48ba 100644
--- a/AsbCloudWebApi/Controllers/AdminUserRoleController.cs
+++ b/AsbCloudWebApi/Controllers/AdminUserRoleController.cs
@@ -1,4 +1,5 @@
using AsbCloudApp.Data;
+using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@@ -12,9 +13,9 @@ namespace AsbCloudWebApi.Controllers
[Route("api/admin/role")]
[ApiController]
[Authorize]
- public class AdminUserRoleController : CrudController
+ public class AdminUserRoleController : CrudController
{
- public AdminUserRoleController(IUserRoleService service)
+ public AdminUserRoleController(IUserRoleRepository service)
: base(service)
{
UpdateForbidAsync = async (dto, token) =>