using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.Cache; using Mapster; using AsbCloudApp.Services; using System; namespace AsbCloudInfrastructure.Services { public class UserRoleService : IUserRoleService { private readonly CacheTable cacheUserRoles; private readonly CacheTable cacheUserRolePermissions; public ISet Includes { get; } = new SortedSet(); public UserRoleService(IAsbCloudDbContext context, CacheDb cacheDb) { cacheUserRoles = cacheDb.GetCachedTable((AsbCloudDbContext)context, nameof(UserRole.RelationUserRolePermissions)); cacheUserRolePermissions = cacheDb.GetCachedTable((AsbCloudDbContext)context, nameof(RelationUserRolePermission.Permission)); } 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 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 async Task GetAsync(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 GetByNameAsync(string name, CancellationToken token = default) { var entity = await cacheUserRoles.FirstOrDefaultAsync(r => r.Caption == name, 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 ArgumentException("Invalid role names", nameof(names)); var dtos = entities.Select(Convert); return dtos; } public async Task UpdateAsync(int id, UserRoleDto dto, CancellationToken token = default) { if (dto.Id != id) { var exist = await cacheUserRoles.ContainsAsync(i => i.Id == dto.Id, token) .ConfigureAwait(false); if (exist) return -1; await cacheUserRoles.RemoveAsync(i => i.Id == id, token) .ConfigureAwait(false); } var entity = Convert(dto); await UpdatePermissionsAsync(dto, token); await cacheUserRoles.UpsertAsync(entity, token) .ConfigureAwait(false); return dto.Id; } public List 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; } private async Task UpdatePermissionsAsync(UserRoleDto roleDto, CancellationToken token) { if (roleDto?.Permissions is null) return; await cacheUserRolePermissions.RemoveAsync(r => r.IdUserRole == roleDto.Id, token) .ConfigureAwait(false); if (!roleDto.Permissions.Any()) return; var newRelationRoleToPermission = roleDto.Permissions.Select(p => new RelationUserRolePermission { IdPermission = p.Id, IdUserRole = roleDto.Id, }); await cacheUserRolePermissions.InsertAsync(newRelationRoleToPermission, token) .ConfigureAwait(false); } 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 = cacheUserRolePermissions .FirstOrDefault(p => p.Permission?.Name.ToLower() == permissionName.ToLower()) ?.Permission; if (permissionInfo is null) return false; 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 (userRole.IdParent is not null && recursionLevel > 0) { var parentRole = cacheUserRoles.FirstOrDefault(p => p.Id == userRole.IdParent); return HasPermission(parentRole, idPermission, --recursionLevel); } 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 = cacheUserRolePermissions .Where(r => entity.Id == r.IdUserRole) .Select(r => Convert(r.Permission)); } return dto; } private static PermissionDto Convert(Permission entity) { var dto = entity.Adapt(); return dto; } } }