Revert "CS2-123: Changed role permissions to bit collection"

This reverts commit ad34e6445c.
This commit is contained in:
KharchenkoVladimir 2021-11-29 12:39:28 +05:00
parent ad34e6445c
commit 2d9388cb2a
13 changed files with 226 additions and 3075 deletions

View File

@ -0,0 +1,9 @@
namespace AsbCloudApp.Data
{
public class PermissionDto
{
public int Id { get; set; }
public string Caption { get; set; }
public int Type { get; set; }
}
}

View File

@ -6,8 +6,10 @@ namespace AsbCloudApp.Data
{ {
public int Id { get; set; } public int Id { get; set; }
public string Caption { get; set; } public string Caption { get; set; }
public int RoleType { get; set; }
public int IdParent { get; set; } public int IdParent { get; set; }
public long Permissions { get; set; } public int RoleType { get; set; }
public virtual ICollection<UserDto> Users { get; set; }
public IEnumerable<int> PermissionIds { get; set; }
public IEnumerable<PermissionDto> Permissions { get; set; }
} }
} }

View File

@ -6,7 +6,8 @@ namespace AsbCloudApp.Data
{ {
public int Id { get; set; } public int Id { get; set; }
public string CompanyName { get; set; } public string CompanyName { get; set; }
public IDictionary<string, long> Roles { get; set; } public IDictionary<string, int> Permissions { get; set; }
public IEnumerable<string> RoleNames { get; set; }
public string Token { get; set; } public string Token { get; set; }
} }
} }

View File

@ -1,133 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace AsbCloudDb.Migrations
{
public partial class Changed_Permissions_To_Bit_Collection : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "t_relation_user_role_permission");
migrationBuilder.DropColumn(
name: "caption",
table: "t_permission");
migrationBuilder.DropColumn(
name: "type",
table: "t_permission");
migrationBuilder.AlterTable(
name: "t_permission",
comment: "Описание битов разрешений для ролей пользователей",
oldComment: "Разрешения на доступ к данным");
migrationBuilder.AddColumn<long>(
name: "permissions",
table: "t_user_role",
type: "bigint",
nullable: false,
defaultValue: 0L,
comment: "Десятичное число, хранящее список разрешений для роли (в двоичном виде)");
migrationBuilder.AddColumn<string>(
name: "description",
table: "t_permission",
type: "character varying(255)",
maxLength: 255,
nullable: true,
comment: "Описание разрешений");
migrationBuilder.AddColumn<string>(
name: "index",
table: "t_permission",
type: "text",
nullable: true,
comment: "Порядковый номер бита. \n В нем 0-запрещено, 1-разрешено.");
migrationBuilder.InsertData(
table: "t_relation_user_user_role",
columns: new[] { "id", "id_user", "id_user_role" },
values: new object[] { 1, 1, 2 });
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "t_relation_user_user_role",
keyColumn: "id",
keyValue: 1);
migrationBuilder.DropColumn(
name: "permissions",
table: "t_user_role");
migrationBuilder.DropColumn(
name: "description",
table: "t_permission");
migrationBuilder.DropColumn(
name: "index",
table: "t_permission");
migrationBuilder.AlterTable(
name: "t_permission",
comment: "Разрешения на доступ к данным",
oldComment: "Описание битов разрешений для ролей пользователей");
migrationBuilder.AddColumn<string>(
name: "caption",
table: "t_permission",
type: "character varying(255)",
maxLength: 255,
nullable: true,
comment: "Название");
migrationBuilder.AddColumn<int>(
name: "type",
table: "t_permission",
type: "integer",
nullable: false,
defaultValue: 0,
comment: "1-чтение, 2-запись, 3-чтение и запись");
migrationBuilder.CreateTable(
name: "t_relation_user_role_permission",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
id_permission = table.Column<int>(type: "integer", nullable: false),
id_user_role = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_t_relation_user_role_permission", x => x.id);
table.ForeignKey(
name: "FK_t_relation_user_role_permission_t_permission_id_permission",
column: x => x.id_permission,
principalTable: "t_permission",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_relation_user_role_permission_t_user_role_id_user_role",
column: x => x.id_user_role,
principalTable: "t_user_role",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "Отношение ролей пользователей и разрешений доступа");
migrationBuilder.CreateIndex(
name: "IX_t_relation_user_role_permission_id_permission",
table: "t_relation_user_role_permission",
column: "id_permission");
migrationBuilder.CreateIndex(
name: "IX_t_relation_user_role_permission_id_user_role",
table: "t_relation_user_role_permission",
column: "id_user_role");
}
}
}

View File

@ -689,23 +689,23 @@ namespace AsbCloudDb.Migrations
.HasColumnName("id") .HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Description") b.Property<string>("Caption")
.HasMaxLength(255) .HasMaxLength(255)
.HasColumnType("character varying(255)") .HasColumnType("character varying(255)")
.HasColumnName("description") .HasColumnName("caption")
.HasComment("Описание разрешений"); .HasComment("Название");
b.Property<string>("Index") b.Property<int>("Type")
.HasColumnType("text") .HasColumnType("integer")
.HasColumnName("index") .HasColumnName("type")
.HasComment("Порядковый номер бита. \n В нем 0-запрещено, 1-разрешено."); .HasComment("1-чтение, 2-запись, 3-чтение и запись");
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("t_permission"); b.ToTable("t_permission");
b b
.HasComment("Описание битов разрешений для ролей пользователей"); .HasComment("Разрешения на доступ к данным");
}); });
modelBuilder.Entity("AsbCloudDb.Model.RelationCompanyWell", b => modelBuilder.Entity("AsbCloudDb.Model.RelationCompanyWell", b =>
@ -728,6 +728,34 @@ namespace AsbCloudDb.Migrations
.HasComment("отношение скважин и компаний"); .HasComment("отношение скважин и компаний");
}); });
modelBuilder.Entity("AsbCloudDb.Model.RelationUserRolePermission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("IdPermission")
.HasColumnType("integer")
.HasColumnName("id_permission");
b.Property<int>("IdUserRole")
.HasColumnType("integer")
.HasColumnName("id_user_role");
b.HasKey("Id");
b.HasIndex("IdPermission");
b.HasIndex("IdUserRole");
b.ToTable("t_relation_user_role_permission");
b
.HasComment("Отношение ролей пользователей и разрешений доступа");
});
modelBuilder.Entity("AsbCloudDb.Model.RelationUserUserRole", b => modelBuilder.Entity("AsbCloudDb.Model.RelationUserUserRole", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -754,14 +782,6 @@ namespace AsbCloudDb.Migrations
b b
.HasComment("Отношение пользователей и ролей"); .HasComment("Отношение пользователей и ролей");
b.HasData(
new
{
Id = 1,
IdUser = 1,
IdUserRole = 2
});
}); });
modelBuilder.Entity("AsbCloudDb.Model.ReportProperty", b => modelBuilder.Entity("AsbCloudDb.Model.ReportProperty", b =>
@ -1700,11 +1720,6 @@ namespace AsbCloudDb.Migrations
.HasColumnName("id_parent") .HasColumnName("id_parent")
.HasComment("От какой роли унаследована данная роль"); .HasComment("От какой роли унаследована данная роль");
b.Property<long>("Permissions")
.HasColumnType("bigint")
.HasColumnName("permissions")
.HasComment("Десятичное число, хранящее список разрешений для роли (в двоичном виде)");
b.Property<int>("RoleType") b.Property<int>("RoleType")
.HasColumnType("integer") .HasColumnType("integer")
.HasColumnName("role_type") .HasColumnName("role_type")
@ -1723,7 +1738,6 @@ namespace AsbCloudDb.Migrations
Id = 1, Id = 1,
Caption = "Администратор", Caption = "Администратор",
IdParent = 0, IdParent = 0,
Permissions = 0L,
RoleType = 0 RoleType = 0
}, },
new new
@ -1731,7 +1745,6 @@ namespace AsbCloudDb.Migrations
Id = 2, Id = 2,
Caption = "Пользователь", Caption = "Пользователь",
IdParent = 0, IdParent = 0,
Permissions = 0L,
RoleType = 0 RoleType = 0
}); });
}); });
@ -2544,6 +2557,25 @@ namespace AsbCloudDb.Migrations
b.Navigation("Well"); b.Navigation("Well");
}); });
modelBuilder.Entity("AsbCloudDb.Model.RelationUserRolePermission", b =>
{
b.HasOne("AsbCloudDb.Model.Permission", "Permission")
.WithMany("RelationUserRolesPermissions")
.HasForeignKey("IdPermission")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.UserRole", "UserRole")
.WithMany("RelationUserRolesPermissions")
.HasForeignKey("IdUserRole")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Permission");
b.Navigation("UserRole");
});
modelBuilder.Entity("AsbCloudDb.Model.RelationUserUserRole", b => modelBuilder.Entity("AsbCloudDb.Model.RelationUserUserRole", b =>
{ {
b.HasOne("AsbCloudDb.Model.User", "User") b.HasOne("AsbCloudDb.Model.User", "User")
@ -2787,6 +2819,11 @@ namespace AsbCloudDb.Migrations
b.Navigation("Measures"); b.Navigation("Measures");
}); });
modelBuilder.Entity("AsbCloudDb.Model.Permission", b =>
{
b.Navigation("RelationUserRolesPermissions");
});
modelBuilder.Entity("AsbCloudDb.Model.Telemetry", b => modelBuilder.Entity("AsbCloudDb.Model.Telemetry", b =>
{ {
b.Navigation("Analysis"); b.Navigation("Analysis");
@ -2815,6 +2852,8 @@ namespace AsbCloudDb.Migrations
modelBuilder.Entity("AsbCloudDb.Model.UserRole", b => modelBuilder.Entity("AsbCloudDb.Model.UserRole", b =>
{ {
b.Navigation("RelationUserRolesPermissions");
b.Navigation("RelationUsersUserRoles"); b.Navigation("RelationUsersUserRoles");
}); });

View File

@ -39,6 +39,7 @@ namespace AsbCloudDb.Model
public virtual DbSet<DrillParams> DrillParams { get; set; } public virtual DbSet<DrillParams> DrillParams { get; set; }
public virtual DbSet<DrillFlowChart> DrillFlowChart { get; set; } public virtual DbSet<DrillFlowChart> DrillFlowChart { get; set; }
public virtual DbSet<RelationUserUserRole> RelationUserUserRoles { get; set; } public virtual DbSet<RelationUserUserRole> RelationUserUserRoles { get; set; }
public virtual DbSet<RelationUserRolePermission> RelationUserRolesPermissions { get; set; }
public virtual DbSet<Permission> Permissions { get; set; } public virtual DbSet<Permission> Permissions { get; set; }
//var options = new DbContextOptionsBuilder<AsbCloudDbContext>() //var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
@ -273,13 +274,6 @@ namespace AsbCloudDb.Model
}); });
}); });
modelBuilder.Entity<RelationUserUserRole>(entity =>
{
entity.HasData(new List<RelationUserUserRole>{
new RelationUserUserRole{ Id = 1, IdUser = 1, IdUserRole = 2 }
});
});
modelBuilder.Entity<Company>(entity => modelBuilder.Entity<Company>(entity =>
{ {
entity.HasData(new List<Company>{ entity.HasData(new List<Company>{

View File

@ -37,6 +37,7 @@ namespace AsbCloudDb.Model
DbSet<DrillParams> DrillParams { get; set; } DbSet<DrillParams> DrillParams { get; set; }
DbSet<DrillFlowChart> DrillFlowChart { get; set; } DbSet<DrillFlowChart> DrillFlowChart { get; set; }
DbSet<RelationUserUserRole> RelationUserUserRoles { get; set; } DbSet<RelationUserUserRole> RelationUserUserRoles { get; set; }
DbSet<RelationUserRolePermission> RelationUserRolesPermissions { get; set; }
DbSet<Permission> Permissions { get; set; } DbSet<Permission> Permissions { get; set; }
DatabaseFacade Database { get; } DatabaseFacade Database { get; }

View File

@ -1,22 +1,25 @@
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace AsbCloudDb.Model namespace AsbCloudDb.Model
{ {
[Table("t_permission"), Comment("Описание битов разрешений для ролей пользователей")] [Table("t_permission"), Comment("Разрешения на доступ к данным")]
public class Permission public class Permission
{ {
[Key] [Key]
[Column("id")] [Column("id")]
public int Id { get; set; } public int Id { get; set; }
[Column("index"), Comment("Порядковый номер бита. \n В нем 0-запрещено, 1-разрешено.")] [Column("caption"), Comment("Название")]
public string Index { get; set; }
[Column("description"), Comment("Описание разрешений")]
[StringLength(255)] [StringLength(255)]
public string Description { get; set; } public string Caption { get; set; }
[Column("type"), Comment("1-чтение, 2-запись, 3-чтение и запись")]
public int Type { get; set; }
[InverseProperty(nameof(RelationUserRolePermission.Permission))]
public virtual ICollection<RelationUserRolePermission> RelationUserRolesPermissions { get; set; }
} }
} }

View File

@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudDb.Model
{
[Table("t_relation_user_role_permission"), Comment("Отношение ролей пользователей и разрешений доступа")]
public class RelationUserRolePermission
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("id_user_role")]
public int IdUserRole { get; set; }
[Column("id_permission")]
public int IdPermission { get; set; }
[ForeignKey(nameof(IdUserRole))]
[InverseProperty(nameof(Model.UserRole.RelationUserRolesPermissions))]
public virtual UserRole UserRole { get; set; }
[ForeignKey(nameof(IdPermission))]
[InverseProperty(nameof(Model.Permission.RelationUserRolesPermissions))]
public virtual Permission Permission { get; set; }
}
}

View File

@ -1,8 +1,7 @@
using System.Text.Json.Serialization; using Microsoft.EntityFrameworkCore;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace AsbCloudDb.Model namespace AsbCloudDb.Model
@ -24,12 +23,11 @@ namespace AsbCloudDb.Model
[Column("id_parent"), Comment("От какой роли унаследована данная роль")] [Column("id_parent"), Comment("От какой роли унаследована данная роль")]
public int IdParent { get; set; } public int IdParent { get; set; }
[Column("permissions"), Comment("Десятичное число, хранящее список разрешений для роли (в двоичном виде)")]
public long Permissions { get; set; }
[JsonIgnore]
[InverseProperty(nameof(RelationUserUserRole.UserRole))] [InverseProperty(nameof(RelationUserUserRole.UserRole))]
public virtual ICollection<RelationUserUserRole> RelationUsersUserRoles { get; set; } public virtual ICollection<RelationUserUserRole> RelationUsersUserRoles { get; set; }
[InverseProperty(nameof(RelationUserRolePermission.UserRole))]
public virtual ICollection<RelationUserRolePermission> RelationUserRolesPermissions { get; set; }
} }
} }

View File

@ -21,6 +21,8 @@ namespace AsbCloudInfrastructure.Services
private readonly IAsbCloudDbContext db; private readonly IAsbCloudDbContext db;
private readonly CacheTable<UserRole> cacheUserRoles; private readonly CacheTable<UserRole> cacheUserRoles;
private readonly CacheTable<RelationUserUserRole> cacheUsersUserRoles; private readonly CacheTable<RelationUserUserRole> cacheUsersUserRoles;
private readonly CacheTable<Permission> cachePermissions;
private readonly CacheTable<RelationUserRolePermission> cacheUserRolesPermissions;
public const string issuer = "a"; public const string issuer = "a";
public const string audience = "a"; public const string audience = "a";
@ -40,6 +42,8 @@ namespace AsbCloudInfrastructure.Services
this.db = db; this.db = db;
cacheUserRoles = cacheDb.GetCachedTable<UserRole>((AsbCloudDbContext)db); cacheUserRoles = cacheDb.GetCachedTable<UserRole>((AsbCloudDbContext)db);
cacheUsersUserRoles = cacheDb.GetCachedTable<RelationUserUserRole>((AsbCloudDbContext)db); cacheUsersUserRoles = cacheDb.GetCachedTable<RelationUserUserRole>((AsbCloudDbContext)db);
cachePermissions = cacheDb.GetCachedTable<Permission>((AsbCloudDbContext)db);
cacheUserRolesPermissions = cacheDb.GetCachedTable<RelationUserRolePermission>((AsbCloudDbContext)db);
hashAlgoritm = SHA384.Create(); hashAlgoritm = SHA384.Create();
rnd = new Random((int)(DateTime.Now.Ticks % 2147480161)); rnd = new Random((int)(DateTime.Now.Ticks % 2147480161));
} }
@ -53,7 +57,9 @@ namespace AsbCloudInfrastructure.Services
if (identity == default || user.State == 0) if (identity == default || user.State == 0)
return null; return null;
var userRoles = GetUserRoles(user.Id); var idCaptionRoles = GetUserRolesIdsNames(user.Id);
var userPermissions = GetUserPermissions(idCaptionRoles.Select(r => r.Id));
return new UserTokenDto return new UserTokenDto
{ {
@ -62,7 +68,8 @@ namespace AsbCloudInfrastructure.Services
CompanyName = user.Company.Caption, CompanyName = user.Company.Caption,
Login = user.Login, Login = user.Login,
Patronymic = user.Patronymic, Patronymic = user.Patronymic,
Roles = userRoles, RoleNames = idCaptionRoles.Select(r => r.Caption),
Permissions = userPermissions,
Surname = user.Surname, Surname = user.Surname,
Token = MakeToken(identity.Claims), Token = MakeToken(identity.Claims),
}; };
@ -170,14 +177,22 @@ namespace AsbCloudInfrastructure.Services
return new JwtSecurityTokenHandler().WriteToken(jwt); return new JwtSecurityTokenHandler().WriteToken(jwt);
} }
private IDictionary<string, long> GetUserRoles(int idUser) private IEnumerable<(int Id, string Caption)> GetUserRolesIdsNames(int idUser)
{ {
var userRolesIds = cacheUsersUserRoles.Where(r => var userRolesIds = cacheUsersUserRoles.Where(r =>
r.IdUser == idUser).Select(r => r.IdUserRole); r.IdUser == idUser).Select(r => r.IdUserRole);
return cacheUserRoles.Where(r => userRolesIds.Contains(r.Id)) return cacheUserRoles.Where(r => userRolesIds.Contains(r.Id))
.Select(r => (r.Caption, r.Permissions)) .Select(r => (r.Id, r.Caption));
.ToDictionary(k => k.Caption, v => v.Permissions); }
private IDictionary<string, int> GetUserPermissions(IEnumerable<int> idRoles)
{
var userPermissionIds = cacheUserRolesPermissions.Where(p =>
idRoles.Contains(p.IdUserRole)).Select(r => r.IdPermission);
return cachePermissions.Where(r => userPermissionIds.Contains(r.Id))
.ToDictionary(k => k.Caption, v => v.Type);
} }
private async Task<(ClaimsIdentity Identity, User User)> GetClaimsUserAsync(string login, private async Task<(ClaimsIdentity Identity, User User)> GetClaimsUserAsync(string login,
@ -195,8 +210,8 @@ namespace AsbCloudInfrastructure.Services
if (!CheckPassword(user.PasswordHash, password)) if (!CheckPassword(user.PasswordHash, password))
return default; return default;
var userRolesNames = GetUserRoles(user.Id) var userRolesNames = GetUserRolesIdsNames(user.Id)
.Select(r => r.Key); .Select(r => r.Caption);
var claims = new List<Claim> var claims = new List<Claim>
{ {
@ -205,11 +220,9 @@ namespace AsbCloudInfrastructure.Services
new Claim(claimNameidCompany, user.IdCompany.ToString()), new Claim(claimNameidCompany, user.IdCompany.ToString()),
}; };
claims.AddRange(userRolesNames.Select(roleName => claims.AddRange(userRolesNames.Select(roleName => new Claim(ClaimsIdentity.DefaultRoleClaimType, roleName)));
new Claim(ClaimsIdentity.DefaultRoleClaimType, roleName)));
var claimsIdentity = new ClaimsIdentity(claims, "Token", var claimsIdentity = new ClaimsIdentity(claims, "Token", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
return (claimsIdentity, user); return (claimsIdentity, user);
} }

View File

@ -1,6 +1,6 @@
using System; using System.Collections.Generic;
using System.Collections;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data; using AsbCloudApp.Data;
@ -13,11 +13,16 @@ namespace AsbCloudInfrastructure.Services
public class UserRoleService : CrudServiceBase<UserRoleDto, UserRole> public class UserRoleService : CrudServiceBase<UserRoleDto, UserRole>
{ {
private readonly CacheTable<UserRole> cacheUserRoles; private readonly CacheTable<UserRole> cacheUserRoles;
private readonly CacheTable<Permission> cachePermissions;
private readonly CacheTable<RelationUserRolePermission> cacheUserRolesPermissions;
private int counter = 0; private int counter = 0;
public UserRoleService(IAsbCloudDbContext context, CacheDb cacheDb) : base(context) public UserRoleService(IAsbCloudDbContext context, CacheDb cacheDb) : base(context)
{ {
cacheUserRoles = cacheDb.GetCachedTable<UserRole>((AsbCloudDbContext)context); cacheUserRoles = cacheDb.GetCachedTable<UserRole>((AsbCloudDbContext)context);
cachePermissions = cacheDb.GetCachedTable<Permission>((AsbCloudDbContext)context);
cacheUserRolesPermissions =
cacheDb.GetCachedTable<RelationUserRolePermission>((AsbCloudDbContext)context);
} }
public override async Task<PaginationContainer<UserRoleDto>> GetPageAsync(int skip = 0, public override async Task<PaginationContainer<UserRoleDto>> GetPageAsync(int skip = 0,
@ -25,51 +30,97 @@ namespace AsbCloudInfrastructure.Services
{ {
var rolesDtos = await base.GetPageAsync(skip, take,token); var rolesDtos = await base.GetPageAsync(skip, take,token);
rolesDtos.Items = rolesDtos.Items.Select(FillUserRoleWithPermissions).ToList();
return rolesDtos; return rolesDtos;
} }
public override async Task<UserRoleDto> GetAsync(int id, CancellationToken token = default)
{
var roleDto = await base.GetAsync(id,token);
return roleDto is null
? null
: FillUserRoleWithPermissions(roleDto);
}
public override async Task<int> InsertAsync(UserRoleDto dto, CancellationToken token = default) public override async Task<int> InsertAsync(UserRoleDto dto, CancellationToken token = default)
{ {
dto.Permissions = GetAncestorsPermissions(dto, ref counter); dto.PermissionIds = GetAncestorsPermissionIds(dto, ref counter);
return await base.InsertAsync(dto, token); var newRoleId = await base.InsertAsync(dto, token);
if (dto.PermissionIds == default)
return newRoleId;
foreach (var pId in dto.PermissionIds)
{
var relation = new RelationUserRolePermission()
{
IdUserRole = newRoleId,
IdPermission = pId
};
context.RelationUserRolesPermissions.Add(relation);
}
return await context.SaveChangesAsync(token);
} }
private long GetAncestorsPermissions(UserRoleDto currentRoleDto, ref int counter) public override async Task<int> UpdateAsync(int id, UserRoleDto item, CancellationToken token = default)
{ {
if (currentRoleDto.IdParent == default) var result = await base.UpdateAsync(id, item, token);
return currentRoleDto.Permissions;
if (item.PermissionIds == default)
return result;
await cacheUserRolesPermissions.RemoveAsync(r => r.IdUserRole == item.Id, token)
.ConfigureAwait(false);
var newRelations = item.PermissionIds.Select(p => new RelationUserRolePermission()
{
IdUserRole = item.Id,
IdPermission = p
});
await cacheUserRolesPermissions.InsertAsync(newRelations, token);
return result;
}
private UserRoleDto FillUserRoleWithPermissions(UserRoleDto roleDto)
{
var rolePermissionIds = cacheUserRolesPermissions.Where(c =>
c.IdUserRole == roleDto.Id).Select(p => p.IdPermission);
roleDto.Permissions = cachePermissions.Where(permission => rolePermissionIds.Contains(permission.Id))
.Adapt<PermissionDto>();
return roleDto;
}
private IEnumerable<int> GetAncestorsPermissionIds(UserRoleDto userRoleDto, ref int counter)
{
var idParent = userRoleDto.IdParent;
var resultPermissionsIds = userRoleDto.PermissionIds ?? new List<int>();
if (idParent == default)
return resultPermissionsIds;
if (counter > 10) if (counter > 10)
{ {
Trace.WriteLine($"User role with id: {currentRoleDto.Id} has more than 10 parents"); Trace.WriteLine($"User role with id: {userRoleDto.Id} has more than 10 nested parents");
return currentRoleDto.Permissions; return resultPermissionsIds;
} }
var parentRole = cacheUserRoles.FirstOrDefault(r => r.Id == currentRoleDto.IdParent) var parentRole = cacheUserRoles.FirstOrDefault(r => r.Id == idParent)
.Adapt<UserRoleDto>(); .Adapt<UserRoleDto>();
var parentRolePermissionsIds = cacheUserRolesPermissions.Where(p =>
parentRole.Permissions = MakeBitwiseOr(currentRoleDto.Permissions, parentRole.Permissions); p.IdUserRole == parentRole.Id).Select(perm => perm.IdPermission);
parentRole.PermissionIds = resultPermissionsIds.Union(parentRolePermissionsIds);
counter++; counter++;
return GetAncestorsPermissions(parentRole, ref counter); return GetAncestorsPermissionIds(parentRole, ref counter);
}
private static long MakeBitwiseOr(long currentNum, long parentNum)
{
var parentBytes = BitConverter.GetBytes(parentNum);
var parentBits = new BitArray(parentBytes);
var currentBytes = BitConverter.GetBytes(currentNum);
var currentBits = new BitArray(currentBytes);
var resultBits = currentBits.Or(parentBits);
var resultBytes = new byte[8];
resultBits.CopyTo(resultBytes, 0);
return BitConverter.ToInt64(resultBytes);
} }
} }
} }