diff --git a/DepartmentPortal/Common/CommonTools/Attributes/ViewModelPropertyAttribute.cs b/DepartmentPortal/Common/CommonTools/Attributes/ViewModelPropertyAttribute.cs new file mode 100644 index 0000000..3e2ea0c --- /dev/null +++ b/DepartmentPortal/Common/CommonTools/Attributes/ViewModelPropertyAttribute.cs @@ -0,0 +1,36 @@ +using System; + +namespace CommonTools.Attributes +{ + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] + public class ViewModelPropertyAttribute : Attribute + { + /// + /// Название на форме + /// + public string DisplayName { get; set; } + + /// + /// Скрывать или нет + /// + public bool IsHide { get; set; } + + /// + /// Ширина колонки + /// + public int ColumnWidth { get; set; } + + /// + /// Конструктор + /// + /// Название на форме + /// Скрывать или нет + /// Ширина колонки + public ViewModelPropertyAttribute(string displayName, int columnWidth, bool isHide = false) + { + DisplayName = displayName; + ColumnWidth = columnWidth; + IsHide = isHide; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/CommonTools/OperationResultModels/OperationResultModel.cs b/DepartmentPortal/Common/CommonTools/OperationResultModels/OperationResultModel.cs index 93d1616..ab9056b 100644 --- a/DepartmentPortal/Common/CommonTools/OperationResultModels/OperationResultModel.cs +++ b/DepartmentPortal/Common/CommonTools/OperationResultModels/OperationResultModel.cs @@ -25,7 +25,7 @@ namespace CommonTools.OperationResultModels public List<(string Title, string Message)> Errors { get; private set; } /// - /// Какой-то объект, получаемый по результатам операции (например, id) + /// Объект, получаемый по результатам операции /// public object Result { get; private set; } @@ -38,42 +38,4 @@ namespace CommonTools.OperationResultModels StatusCode = ResultServiceStatusCode.Success; } } - - /// - /// Результат любой операции - /// - /// - public class OperationResultModel - where T : ElementViewModel - { - /// - /// Успешность операции - /// - public bool IsSucceeded { get; private set; } - - /// - /// Статус операции - /// - public ResultServiceStatusCode StatusCode { get; private set; } - - /// - /// Спсиок ошибок - /// - public List> Errors { get; private set; } - - /// - /// Какой-то объект, получаемый по результатам операции (например, id) - /// - public T Result { get; private set; } - - /// - /// Конструктор по умолчанию - /// - public OperationResultModel() - { - Errors = new List>(); - IsSucceeded = true; - StatusCode = 0; - } - } } \ No newline at end of file diff --git a/DepartmentPortal/Common/CommonTools/ViewModels/ElementViewModel.cs b/DepartmentPortal/Common/CommonTools/ViewModels/ElementViewModel.cs index 1106ed9..1479933 100644 --- a/DepartmentPortal/Common/CommonTools/ViewModels/ElementViewModel.cs +++ b/DepartmentPortal/Common/CommonTools/ViewModels/ElementViewModel.cs @@ -1,4 +1,5 @@ -using System; +using CommonTools.Attributes; +using System; namespace CommonTools.ViewModels { @@ -7,6 +8,7 @@ namespace CommonTools.ViewModels /// public class ElementViewModel { + [ViewModelProperty("Идентификатор", 1, true)] public Guid Id { get; set; } } } \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/DatabaseContext.cs b/DepartmentPortal/Common/DatabaseCore/DatabaseContext.cs new file mode 100644 index 0000000..7ef1c95 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/DatabaseContext.cs @@ -0,0 +1,33 @@ +using DatabaseCore.Models.Security; +using Microsoft.EntityFrameworkCore; + +namespace DatabaseCore +{ + public class DatabaseContext : DbContext + { + public DatabaseContext() : base() { } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (optionsBuilder.IsConfigured == false) + { +#if RELEASE + var connectionString = ModelTools.ServiceProvider.ServiceProviderLoader.GetConfigData("connectionString"); + optionsBuilder.UseSqlServer(connectionString); +#endif + +#if DEBUG + optionsBuilder.UseSqlServer(@"Data Source=CHESHIR\SQLEXPRESS;Initial Catalog=DepartmentDatabasePortal;persist security info=True;user id=admin;password=cheshirSA123;MultipleActiveResultSets=True;"); +#endif + } + base.OnConfiguring(optionsBuilder); + } + + + public virtual DbSet Accesses { set; get; } + public virtual DbSet EnviromentSettings { set; get; } + public virtual DbSet Roles { set; get; } + public virtual DbSet Users { set; get; } + public virtual DbSet UserRoles { set; get; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/DatabaseCore.csproj b/DepartmentPortal/Common/DatabaseCore/DatabaseCore.csproj new file mode 100644 index 0000000..b5aca4a --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/DatabaseCore.csproj @@ -0,0 +1,21 @@ + + + + net5.0 + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/DepartmentPortal/Common/DatabaseCore/DatabaseManager.cs b/DepartmentPortal/Common/DatabaseCore/DatabaseManager.cs new file mode 100644 index 0000000..6bdd322 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/DatabaseManager.cs @@ -0,0 +1,13 @@ +namespace DatabaseCore +{ + /// + /// Работа с БД + /// + public static class DatabaseManager + { + /// + /// Получение объекта от класса DbContext + /// + public static DatabaseContext GetContext => new(); + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/Migrations/20210326072923_AddSecurityModels.Designer.cs b/DepartmentPortal/Common/DatabaseCore/Migrations/20210326072923_AddSecurityModels.Designer.cs new file mode 100644 index 0000000..e9c7b52 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Migrations/20210326072923_AddSecurityModels.Designer.cs @@ -0,0 +1,211 @@ +// +using System; +using DatabaseCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace DatabaseCore.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20210326072923_AddSecurityModels")] + partial class AddSecurityModels + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.4") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("DatabaseCore.Models.Security.Access", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AccessType") + .HasColumnType("int"); + + b.Property("DateCreate") + .HasColumnType("datetime2"); + + b.Property("DateDelete") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("Accesses"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.EnviromentSetting", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Key") + .HasColumnType("nvarchar(max)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("EnviromentSettings"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.Role", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("DateCreate") + .HasColumnType("datetime2"); + + b.Property("DateDelete") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("RoleName") + .HasColumnType("nvarchar(max)"); + + b.Property("RolePriority") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.User", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Avatar") + .HasColumnType("varbinary(max)"); + + b.Property("CountAttempt") + .HasColumnType("int"); + + b.Property("DateBanned") + .HasColumnType("datetime2"); + + b.Property("DateCreate") + .HasColumnType("datetime2"); + + b.Property("DateDelete") + .HasColumnType("datetime2"); + + b.Property("DateLastVisit") + .HasColumnType("datetime2"); + + b.Property("DateLocked") + .HasColumnType("datetime2"); + + b.Property("EmployeeId") + .HasColumnType("uniqueidentifier"); + + b.Property("IsBanned") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LecturerId") + .HasColumnType("uniqueidentifier"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("StudentId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.UserRole", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.Access", b => + { + b.HasOne("DatabaseCore.Models.Security.Role", "Role") + .WithMany("Access") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.UserRole", b => + { + b.HasOne("DatabaseCore.Models.Security.Role", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DatabaseCore.Models.Security.User", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.Role", b => + { + b.Navigation("Access"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.User", b => + { + b.Navigation("UserRoles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DepartmentPortal/Common/DatabaseCore/Migrations/20210326072923_AddSecurityModels.cs b/DepartmentPortal/Common/DatabaseCore/Migrations/20210326072923_AddSecurityModels.cs new file mode 100644 index 0000000..04aafc8 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Migrations/20210326072923_AddSecurityModels.cs @@ -0,0 +1,146 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace DatabaseCore.Migrations +{ + public partial class AddSecurityModels : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "EnviromentSettings", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Key = table.Column(type: "nvarchar(max)", nullable: true), + Value = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_EnviromentSettings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Roles", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + RoleName = table.Column(type: "nvarchar(max)", nullable: true), + RolePriority = table.Column(type: "int", nullable: false), + DateCreate = table.Column(type: "datetime2", nullable: false), + DateDelete = table.Column(type: "datetime2", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Roles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + UserName = table.Column(type: "nvarchar(max)", nullable: true), + PasswordHash = table.Column(type: "nvarchar(max)", nullable: true), + StudentId = table.Column(type: "uniqueidentifier", nullable: true), + LecturerId = table.Column(type: "uniqueidentifier", nullable: true), + EmployeeId = table.Column(type: "uniqueidentifier", nullable: true), + Avatar = table.Column(type: "varbinary(max)", nullable: true), + DateLastVisit = table.Column(type: "datetime2", nullable: true), + IsBanned = table.Column(type: "bit", nullable: false), + DateBanned = table.Column(type: "datetime2", nullable: true), + CountAttempt = table.Column(type: "int", nullable: false), + DateLocked = table.Column(type: "datetime2", nullable: true), + DateCreate = table.Column(type: "datetime2", nullable: false), + DateDelete = table.Column(type: "datetime2", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Accesses", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + RoleId = table.Column(type: "uniqueidentifier", nullable: false), + Operation = table.Column(type: "int", nullable: false), + AccessType = table.Column(type: "int", nullable: false), + DateCreate = table.Column(type: "datetime2", nullable: false), + DateDelete = table.Column(type: "datetime2", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Accesses", x => x.Id); + table.ForeignKey( + name: "FK_Accesses_Roles_RoleId", + column: x => x.RoleId, + principalTable: "Roles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserRoles", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + RoleId = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserRoles", x => x.Id); + table.ForeignKey( + name: "FK_UserRoles_Roles_RoleId", + column: x => x.RoleId, + principalTable: "Roles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_UserRoles_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Accesses_RoleId", + table: "Accesses", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "IX_UserRoles_RoleId", + table: "UserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "IX_UserRoles_UserId", + table: "UserRoles", + column: "UserId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Accesses"); + + migrationBuilder.DropTable( + name: "EnviromentSettings"); + + migrationBuilder.DropTable( + name: "UserRoles"); + + migrationBuilder.DropTable( + name: "Roles"); + + migrationBuilder.DropTable( + name: "Users"); + } + } +} diff --git a/DepartmentPortal/Common/DatabaseCore/Migrations/DatabaseContextModelSnapshot.cs b/DepartmentPortal/Common/DatabaseCore/Migrations/DatabaseContextModelSnapshot.cs new file mode 100644 index 0000000..fe854ca --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Migrations/DatabaseContextModelSnapshot.cs @@ -0,0 +1,209 @@ +// +using System; +using DatabaseCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace DatabaseCore.Migrations +{ + [DbContext(typeof(DatabaseContext))] + partial class DatabaseContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.4") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("DatabaseCore.Models.Security.Access", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AccessType") + .HasColumnType("int"); + + b.Property("DateCreate") + .HasColumnType("datetime2"); + + b.Property("DateDelete") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("Accesses"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.EnviromentSetting", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Key") + .HasColumnType("nvarchar(max)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("EnviromentSettings"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.Role", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("DateCreate") + .HasColumnType("datetime2"); + + b.Property("DateDelete") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("RoleName") + .HasColumnType("nvarchar(max)"); + + b.Property("RolePriority") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.User", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Avatar") + .HasColumnType("varbinary(max)"); + + b.Property("CountAttempt") + .HasColumnType("int"); + + b.Property("DateBanned") + .HasColumnType("datetime2"); + + b.Property("DateCreate") + .HasColumnType("datetime2"); + + b.Property("DateDelete") + .HasColumnType("datetime2"); + + b.Property("DateLastVisit") + .HasColumnType("datetime2"); + + b.Property("DateLocked") + .HasColumnType("datetime2"); + + b.Property("EmployeeId") + .HasColumnType("uniqueidentifier"); + + b.Property("IsBanned") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LecturerId") + .HasColumnType("uniqueidentifier"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("StudentId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.UserRole", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.Access", b => + { + b.HasOne("DatabaseCore.Models.Security.Role", "Role") + .WithMany("Access") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.UserRole", b => + { + b.HasOne("DatabaseCore.Models.Security.Role", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DatabaseCore.Models.Security.User", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.Role", b => + { + b.Navigation("Access"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("DatabaseCore.Models.Security.User", b => + { + b.Navigation("UserRoles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DepartmentPortal/Common/DatabaseCore/Models/BaseEntity.cs b/DepartmentPortal/Common/DatabaseCore/Models/BaseEntity.cs new file mode 100644 index 0000000..4819b48 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Models/BaseEntity.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.Serialization; + +namespace DatabaseCore.Models +{ + /// + /// Базовый набор для сущности + /// + [DataContract] + public class BaseEntity : IdEntity + { + [DataMember] + public DateTime DateCreate { get; set; } + + [DataMember] + public DateTime? DateDelete { get; set; } + + [DataMember] + public bool IsDeleted { get; set; } + + public BaseEntity() : base() + { + DateCreate = DateTime.Now; + DateDelete = null; + IsDeleted = false; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/Models/IdEntity.cs b/DepartmentPortal/Common/DatabaseCore/Models/IdEntity.cs new file mode 100644 index 0000000..eb15cd0 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Models/IdEntity.cs @@ -0,0 +1,24 @@ +using ModelTools.Attributes; +using System; +using System.ComponentModel.DataAnnotations.Schema; +using System.Runtime.Serialization; + +namespace DatabaseCore.Models +{ + /// + /// Тип Id для всеъ сущностей + /// + [DataContract] + public class IdEntity + { + [DataMember] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + [MapConfiguration("Id")] + public Guid Id { get; set; } + + public IdEntity() : base() + { + Id = Guid.NewGuid(); + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/Models/Security/Access.cs b/DepartmentPortal/Common/DatabaseCore/Models/Security/Access.cs new file mode 100644 index 0000000..c4a0b5c --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Models/Security/Access.cs @@ -0,0 +1,38 @@ +using ModelTools.Attributes; +using ModelTools.Enums; +using System; +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; + +namespace DatabaseCore.Models.Security +{ + /// + /// Класс, описывающий возможные действия для роли + /// + [DataContract] + [EntityDescription("Access", "Доступные действия для ролей")] + [EntityDependency("Role", "RoleId", "Доступные дейсвтиия создаются под конкретную роль")] + public class Access : BaseEntity + { + [Required] + [DataMember] + [MapConfiguration("RoleId")] + public Guid RoleId { get; set; } + + [Required] + [DataMember] + [MapConfiguration("Operation")] + public AccessOperation Operation { get; set; } + + [Required] + [DataMember] + [MapConfiguration("AccessType")] + public AccessType AccessType { get; set; } + + //------------------------------------------------------------------------- + + public virtual Role Role { get; set; } + + //------------------------------------------------------------------------- + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/Models/Security/EnviromentSetting.cs b/DepartmentPortal/Common/DatabaseCore/Models/Security/EnviromentSetting.cs new file mode 100644 index 0000000..dfd0fb6 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Models/Security/EnviromentSetting.cs @@ -0,0 +1,21 @@ +using ModelTools.Attributes; +using System.Runtime.Serialization; + +namespace DatabaseCore.Models.Security +{ + /// + /// Класс, описывающий общие настройки системы + /// + [DataContract] + [EntityDescription("EnviromentSetting", "Общие настройки системы")] + public class EnviromentSetting : IdEntity + { + [DataMember] + [MapConfiguration("Key")] + public string Key { get; set; } + + [DataMember] + [MapConfiguration("Value")] + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/Models/Security/Role.cs b/DepartmentPortal/Common/DatabaseCore/Models/Security/Role.cs new file mode 100644 index 0000000..40f4cf2 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Models/Security/Role.cs @@ -0,0 +1,33 @@ +using ModelTools.Attributes; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Runtime.Serialization; + +namespace DatabaseCore.Models.Security +{ + /// + /// Класс, описывающий роль в системе + /// + [DataContract] + [EntityDescription("Role", "Роли в системе")] + public class Role : BaseEntity + { + [DataMember] + [MapConfiguration("RoleName")] + public string RoleName { get; set; } + + [DataMember] + [MapConfiguration("RolePriority")] + public int RolePriority { get; set; } + + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + + [ForeignKey("RoleId")] + public virtual List Access { get; set; } + + [ForeignKey("RoleId")] + public virtual List UserRoles { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/Models/Security/User.cs b/DepartmentPortal/Common/DatabaseCore/Models/Security/User.cs new file mode 100644 index 0000000..6e5aa34 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Models/Security/User.cs @@ -0,0 +1,63 @@ +using ModelTools.Attributes; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Runtime.Serialization; + +namespace DatabaseCore.Models.Security +{ + /// + /// Класс, описывающий пользователя системы + /// + [DataContract] + [EntityDescription("User", "Пользователи системы")] + public class User : BaseEntity + { + [DataMember] + [MapConfiguration("Login")] + public string UserName { get; set; } + + [DataMember] + [MapConfiguration("Password")] + public string PasswordHash { get; set; } + + [DataMember] + [MapConfiguration("StudentId")] + public Guid? StudentId { get; set; } + + [DataMember] + [MapConfiguration("LecturerId")] + public Guid? LecturerId { get; set; } + + [DataMember] + [MapConfiguration("EmployeeId")] + public Guid? EmployeeId { get; set; } + + [DataMember] + [MapConfiguration("Avatar")] + public byte[] Avatar { get; set; } + + [DataMember] + [MapConfiguration("DateLastVisit")] + public DateTime? DateLastVisit { get; set; } + + [DataMember] + [MapConfiguration("IsBanned")] + public bool IsBanned { get; set; } + + [DataMember] + [MapConfiguration("DateBanned")] + public DateTime? DateBanned { get; set; } + + [DataMember] + [MapConfiguration("CountAttempt")] + public int CountAttempt { get; set; } + + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + + [ForeignKey("UserId")] + public virtual List UserRoles { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/Models/Security/UserRole.cs b/DepartmentPortal/Common/DatabaseCore/Models/Security/UserRole.cs new file mode 100644 index 0000000..b2e3bfb --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Models/Security/UserRole.cs @@ -0,0 +1,30 @@ +using ModelTools.Attributes; +using System; +using System.Runtime.Serialization; + +namespace DatabaseCore.Models.Security +{ + /// + /// Связка пользователь - роль + /// + [DataContract] + [EntityDescription("UserRole", "Связь пользователей системы с ролями, которые им назначены")] + [EntityDependency("Role", "RoleId", "К какой роли относится пользователь")] + [EntityDependency("User", "UserId", "К какой роли относится пользователь")] + public class UserRole : BaseEntity + { + [DataMember] + public Guid RoleId { get; set; } + + [DataMember] + public Guid UserId { get; set; } + + //------------------------------------------------------------------------- + + public virtual Role Role { get; set; } + + public virtual User User { get; set; } + + //------------------------------------------------------------------------- + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/Scripts/SecureMigrationScript.cs b/DepartmentPortal/Common/DatabaseCore/Scripts/SecureMigrationScript.cs new file mode 100644 index 0000000..be16bc8 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/Scripts/SecureMigrationScript.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore; + +namespace DatabaseCore.Scripts +{ + /// + /// Скрипты для миграции данных по безопасности + /// + public static class SecureMigrationScript + { + private static readonly string clearMigration = +@"DELETE FROM DepartmentDatabasePortal.dbo.EnviromentSettings +GO +DELETE FROM DepartmentDatabasePortal.dbo.Accesses; +GO +DELETE FROM DepartmentDatabasePortal.dbo.UserRoles; +GO +DELETE FROM DepartmentDatabasePortal.dbo.Users; +GO +DELETE FROM DepartmentDatabasePortal.dbo.Roles; +GO"; + + private static readonly string roleMigration = +@"INSERT INTO DepartmentDatabasePortal.dbo.Roles(Id, RoleName, RolePriority, DateCreate, DateDelete, IsDeleted) +SELECT Id, RoleName, RolePriority, DateCreate, DateDelete, IsDeleted FROM DepartmentDatabaseContext.dbo.DepartmentRoles"; + + private static readonly string userMigration = +@"INSERT INTO DepartmentDatabasePortal.dbo.Users(Id, UserName, PasswordHash, StudentId, LecturerId, Avatar, DateLastVisit, IsBanned, DateBanned, CountAttempt, DateCreate, DateDelete, IsDeleted) +SELECT Id, UserName, PasswordHash, StudentId, LecturerId, Avatar, DateLastVisit, IsLocked, DateBanned, CountAttempt, DateCreate, DateDelete, IsDeleted FROM DepartmentDatabaseContext.dbo.DepartmentUsers"; + + private static readonly string userroleMigration = +@"INSERT INTO DepartmentDatabasePortal.dbo.UserRoles(Id, UserId, RoleId, DateCreate, DateDelete, IsDeleted) +SELECT Id, UserId, RoleId, DateCreate, DateDelete, IsDeleted FROM DepartmentDatabaseContext.dbo.DepartmentUserRoles"; + + private static readonly string accessMigration = +@"INSERT INTO DepartmentDatabasePortal.dbo.Accesses(Id, Operation, AccessType, RoleId, DateCreate, DateDelete, IsDeleted) +SELECT Id, Operation, AccessType, RoleId, DateCreate, DateDelete, IsDeleted FROM DepartmentDatabaseContext.dbo.DepartmentAccesses"; + + private static readonly string enviromentsettingMigration = +@"INSERT INTO DepartmentDatabasePortal.dbo.EnviromentSettings(Id, [Key], [Value]) +SELECT NEWID(), [Key], [Value] FROM DepartmentDatabaseContext.dbo.CurrentSettings"; + + /// + /// Перенос данных по безопасности + /// + /// + public static void RunScript(DbContext context) + { + context.Database.ExecuteSqlRaw(clearMigration, null); + + context.Database.ExecuteSqlRaw(roleMigration, null); + context.Database.ExecuteSqlRaw(userMigration, null); + context.Database.ExecuteSqlRaw(userroleMigration, null); + context.Database.ExecuteSqlRaw(accessMigration, null); + context.Database.ExecuteSqlRaw(enviromentsettingMigration, null); + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/DatabaseCore/SecurityManager.cs b/DepartmentPortal/Common/DatabaseCore/SecurityManager.cs new file mode 100644 index 0000000..2ed76c5 --- /dev/null +++ b/DepartmentPortal/Common/DatabaseCore/SecurityManager.cs @@ -0,0 +1,64 @@ +using DatabaseCore.Models.Security; +using ModelTools.BindingModels; +using ModelTools.Enums; +using ModelTools.Interfaces; +using SecurityBusinessLogic.BusinessLogics; +using System.Linq; + +namespace DatabaseCore +{ + public class SecurityManager : ISecurityManager + { + public string ErrorMessage { get; set; } + + public bool CheckAccess(AccessBindingModel model, AccessOperation operation, AccessType type, string entity) + { + using var context = DatabaseManager.GetContext; + Access access; + if (model != null) + { + // простой просмотр возможен + if (model.SkipCheck && type == AccessType.SimpleView) + { + return true; + } + // если не указан идентификатор пользователя, то смотрим, может он авторизован + if (!model.UserId.HasValue && UserManager.GetInstance.User != null) + { + model.UserId = UserManager.GetInstance.UserId; + } + + var roles = context.UserRoles.Where(x => x.UserId == model.UserId).Select(x => x.Role).OrderByDescending(x => x.RolePriority).ToList(); + if (roles == null) + { + ErrorMessage = $"Не верный пользователь"; + return false; + } + access = context.Accesses.FirstOrDefault(a => a.Operation == operation && roles.Contains(a.Role)); + } + else + { + access = context.Accesses.FirstOrDefault(a => a.Operation == operation && UserManager.GetInstance.Roles.Contains(a.RoleId)); + } + if (access != null) + { + if (access.AccessType >= type) return true; + } + switch (type) + { + case AccessType.FullView: + ErrorMessage = $"Нет доступа на чтение данных по сущности '{entity}'"; + return false; + case AccessType.Change: + ErrorMessage = $"Нет доступа на изменение данных по сущности '{entity}'"; + return false; + case AccessType.Delete: + ErrorMessage = $"Нет доступа на удаление данных по сущности '{entity}'"; + return false; + default: + ErrorMessage = $"Нет доступа по сущности '{entity}'"; + return false; + } + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Attributes/EntityDependencyAttribute.cs b/DepartmentPortal/Common/ModelTools/Attributes/EntityDependencyAttribute.cs new file mode 100644 index 0000000..8640e72 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Attributes/EntityDependencyAttribute.cs @@ -0,0 +1,39 @@ +using System; + +namespace ModelTools.Attributes +{ + /// + /// Описание зависимости сущности от другой сущности (требуется для сохранения и загрузки данных) + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public class EntityDependencyAttribute : Attribute + { + /// + /// Название класса от котрого зависит этот класс + /// + public string ClassName { get; set; } + + /// + /// Название поле в этом классе, которое ссылает на другой класс (идентификатор) + /// + public string ColumnName { get; set; } + + /// + /// Описание зависимости + /// + public string Description { get; set; } + + /// + /// Описание зависимости сущности от другой сущности (требуется для сохранения и загрузки данных) + /// + /// Название класса от котрого зависит этот класс + /// Название поле в этом классе, которое ссылает на другой класс (идентификатор) + /// Описание зависимости + public EntityDependencyAttribute(string className, string columnName, string description) + { + ClassName = className; + ColumnName = columnName; + Description = description; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Attributes/EntityDescriptionAttribute.cs b/DepartmentPortal/Common/ModelTools/Attributes/EntityDescriptionAttribute.cs new file mode 100644 index 0000000..22111b7 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Attributes/EntityDescriptionAttribute.cs @@ -0,0 +1,32 @@ +using System; + +namespace ModelTools.Attributes +{ + /// + /// Описание класса из базы данных, его назначение + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public class EntityDescriptionAttribute : Attribute + { + /// + /// Название сущности, которую описывает класс + /// + public string EntityName { get; set; } + + /// + /// Описание назначения сущности + /// + public string Description { get; set; } + + /// + /// Описание класса из базы данных, его назначение + /// + /// Название сущности, которую описывает класс + /// Описание назначения сущности + public EntityDescriptionAttribute(string entityName, string description) + { + EntityName = entityName; + Description = description; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Attributes/MapConfigurationAttribute.cs b/DepartmentPortal/Common/ModelTools/Attributes/MapConfigurationAttribute.cs new file mode 100644 index 0000000..850fcd3 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Attributes/MapConfigurationAttribute.cs @@ -0,0 +1,32 @@ +using System; + +namespace ModelTools.Attributes +{ + /// + /// Настройка для полей сущности правил маппинга + /// + [AttributeUsage(AttributeTargets.Property)] + public class MapConfigurationAttribute : Attribute + { + /// + /// Название свойства с класса, из которого извлекаем данные + /// + public string PropertyNameFromModel { get; set; } + + /// + /// Сложное свойство (свойствое в другом классе-свойстве) + /// + public bool IsDifficle { get; set; } + + /// + /// Настройка для полей сущности правил маппинга + /// + /// Название свойства с класса, из которого извлекаем данные + /// Сложное свойство (свойствое в другом классе-свойстве) + public MapConfigurationAttribute(string propertyNameFromMModel, bool isDifficle = false) + { + PropertyNameFromModel = propertyNameFromMModel; + IsDifficle = isDifficle; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Attributes/ViewModelPropertyAttribute.cs b/DepartmentPortal/Common/ModelTools/Attributes/ViewModelPropertyAttribute.cs new file mode 100644 index 0000000..a8358fb --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Attributes/ViewModelPropertyAttribute.cs @@ -0,0 +1,68 @@ +using System; + +namespace ModelTools.Attributes +{ + /// + /// Настройка отображения элемента в контролах + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] + public class ViewModelPropertyAttribute : Attribute + { + /// + /// Используется при выводе списка + /// + public bool UseOnList { get; set; } + + /// + /// Используется при выводе элемента + /// + public bool UseOnElement { get; set; } + + /// + /// Название на форме + /// + public string DisplayName { get; set; } + + /// + /// Скрывать или нет при выводе списка + /// + public bool IsHide { get; set; } + + /// + /// Ширина колонки + /// + public int? ColumnWidth { get; set; } + + /// + /// Настройка отображения элемента в контролах + /// + /// Название на форме + /// Используется при выводе списка + /// Используется при выводе элемента + /// Скрывать или нет + public ViewModelPropertyAttribute(string displayName, bool useOnList, bool useOnElement, bool isHide = false) + { + DisplayName = displayName; + UseOnList = useOnList; + UseOnElement = useOnElement; + ColumnWidth = null; + IsHide = isHide; + } + + /// + /// Конструктор + /// + /// Название на форме + /// Используется при выводе списка + /// Используется при выводе элемента + /// Ширина колонки + public ViewModelPropertyAttribute(string displayName, bool useOnList, bool useOnElement, int columnWidth) + { + DisplayName = displayName; + UseOnList = useOnList; + UseOnElement = useOnElement; + ColumnWidth = columnWidth; + IsHide = false; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/BindingModels/AccessBindingModel.cs b/DepartmentPortal/Common/ModelTools/BindingModels/AccessBindingModel.cs new file mode 100644 index 0000000..cda456c --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/BindingModels/AccessBindingModel.cs @@ -0,0 +1,20 @@ +using System; + +namespace ModelTools.BindingModels +{ + /// + /// Информация для доступа к выполнению операций + /// + public class AccessBindingModel + { + /// + /// Пропускать проверку (работает только для получения данных) + /// + public bool SkipCheck { get; set; } + + /// + /// Идентификатор пользователя, который запрашивает выполнение операции + /// + public Guid? UserId { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/BindingModels/GetBindingModel.cs b/DepartmentPortal/Common/ModelTools/BindingModels/GetBindingModel.cs new file mode 100644 index 0000000..c13aa05 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/BindingModels/GetBindingModel.cs @@ -0,0 +1,30 @@ +using System; + +namespace ModelTools.BindingModels +{ + /// + /// Получение записи + /// + public class GetBindingModel : AccessBindingModel + { + /// + /// Идентификатор получаемой записи (для одной записи) + /// + public Guid? Id { get; set; } + + /// + /// Номер страницы, которую получаем (для списка) + /// + public int? PageNumber { get; set; } + + /// + /// Количество записей возвращаемых (для списка) + /// + public int? PageSize { get; set; } + + /// + /// Иной признак, по которму отбираем записи (для списка) + /// + public string PageName { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/BindingModels/SetBindingModel.cs b/DepartmentPortal/Common/ModelTools/BindingModels/SetBindingModel.cs new file mode 100644 index 0000000..894357a --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/BindingModels/SetBindingModel.cs @@ -0,0 +1,15 @@ +using System; + +namespace ModelTools.BindingModels +{ + /// + /// Сохранение записи по идентификатору + /// + public class SetBindingModel : AccessBindingModel + { + /// + /// Идентификатор записи + /// + public Guid Id { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/BusinessLogics/BusinessLogicCore.cs b/DepartmentPortal/Common/ModelTools/BusinessLogics/BusinessLogicCore.cs new file mode 100644 index 0000000..f6adbd0 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/BusinessLogics/BusinessLogicCore.cs @@ -0,0 +1,226 @@ +using ModelTools.BindingModels; +using ModelTools.Enums; +using ModelTools.Interfaces; +using ModelTools.OperationResultModels; +using ModelTools.ViewModels; +using System; +using System.Collections.Generic; + +namespace ModelTools.BusinessLogics +{ + /// + /// Базовый класс для логики сущности + /// + /// + /// + /// + /// + public abstract class BusinessLogicCore + where G : GetBindingModel + where S : SetBindingModel + where L : ListViewModel + where E : ElementViewModel + { + /// + /// Перечень ошибок при выполнении операции + /// + public List<(string Title, string Message)> Errors { get; protected set; } + + protected IEntityService Service { get; set; } + + protected ISecurityManager Security { get; set; } + + protected readonly AccessOperation _serviceOperation; + + protected readonly string _entity; + + public BusinessLogicCore(IEntityService service, string entity, AccessOperation serviceOperation) + { + Service = service; + Errors = new List<(string Title, string Message)>(); + Security = UnityContainerConfigurator.Resolve(); + _entity = entity; + _serviceOperation = serviceOperation; + } + + /// + /// Проверка доступности операции для пользователя + /// + /// + /// + /// + protected bool NoAccess(AccessBindingModel model, AccessType type) + { + if (Security.CheckAccess(model, _serviceOperation, type, _entity)) + { + return false; + } + + Errors.Add(("Ошибка безопасности", Security.ErrorMessage)); + return true; + } + + /// + /// Получение списка записей + /// + /// + /// + public L GetList(G model) + { + Errors.Clear(); + try + { + if (NoAccess(model, AccessType.SimpleView) && NoAccess(model, AccessType.FullView)) + { + return null; + } + var result = Service.Read(model); + if (!result.IsSucceeded) + { + Errors.AddRange(Errors); + return null; + } + + return ConvertToL(result); + } + catch (Exception ex) + { + Errors.Add(("Ошибка получения", ex.Message)); + } + return null; + } + + /// + /// Получение записи + /// + /// + /// + public E GetElement(G model) + { + Errors.Clear(); + try + { + if (NoAccess(model, AccessType.SimpleView) && NoAccess(model, AccessType.FullView)) + { + return null; + } + var result = Service.Read(model); + if (!result.IsSucceeded) + { + Errors.AddRange(Errors); + return null; + } + return ConvertToE(result); + } + catch (Exception ex) + { + Errors.Add(("Ошибка получения", ex.Message)); + } + return null; + } + + /// + /// Создание записи + /// + /// + /// + public E Create(S model) + { + Errors.Clear(); + try + { + if (NoAccess(model, AccessType.Change)) + { + return null; + } + var result = Service.Create(model); + if (!result.IsSucceeded) + { + Errors.AddRange(Errors); + return null; + } + + return ConvertToE(result); + } + catch (Exception ex) + { + Errors.Add(("Ошибка создания", ex.Message)); + } + return null; + } + + /// + /// Изменение записи + /// + /// + /// + public E Update(S model) + { + Errors.Clear(); + try + { + if (NoAccess(model, AccessType.Change)) + { + return null; + } + var result = Service.Update(model); + if (!result.IsSucceeded) + { + Errors.AddRange(Errors); + return null; + } + + return ConvertToE(result); + } + catch (Exception ex) + { + Errors.Add(("Ошибка изменения", ex.Message)); + } + return null; + } + + /// + /// Удаление записи + /// + /// + /// + public bool Delete(G model) + { + Errors.Clear(); + try + { + if (NoAccess(model, AccessType.Delete)) + { + return false; + } + var result = Service.Delete(model); + if (!result.IsSucceeded) + { + Errors.AddRange(Errors); + return false; + } + + return true; + } + catch (Exception ex) + { + Errors.Add(("Ошибка удаления", ex.Message)); + } + return false; + } + + /// + /// Получить список элементов + /// + /// + /// + protected abstract L ConvertToL(OperationResultModel model); + + /// + /// Получить элемент + /// + /// + /// + protected abstract E ConvertToE(OperationResultModel model); + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/BusinessLogics/Mapper.cs b/DepartmentPortal/Common/ModelTools/BusinessLogics/Mapper.cs new file mode 100644 index 0000000..b576561 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/BusinessLogics/Mapper.cs @@ -0,0 +1,100 @@ +using ModelTools.Attributes; +using System; +using System.Reflection; + +namespace ModelTools.BusinessLogics +{ + /// + /// Маппер сущностей + /// + public class Mapper + { + /// + /// Преобразование из одного класса в другой + /// + /// + /// + /// + /// + public static To MapToClass(From obj) where To : class => FillObject(obj, (To)Activator.CreateInstance(typeof(To))); + + /// + /// Преобразование из одного класса в другой + /// + /// + /// + /// + /// + /// + public static To MapToClass(From obj, To newObject) where To : class => FillObject(obj, newObject); + + /// + /// Заполнение объекта + /// + /// + /// + /// + /// + /// + private static To FillObject(From obj, To newObject) + where To : class + { + if (obj == null) + { + return null; + } + + if (newObject == null) + { + return null; + } + var typeFrom = typeof(From); + var typeTo = typeof(To); + var properties = typeTo.GetProperties(); + foreach (var property in properties) + { + var customAttribute = property.GetCustomAttribute(); + if (customAttribute != null) + { + object value = obj; + if (customAttribute.IsDifficle) + { + var props = customAttribute.PropertyNameFromModel.Split('.'); + foreach (var prop in props) + { + var bindingProperty = value.GetType().GetProperty(prop); + if (bindingProperty != null) + { + value = bindingProperty.GetValue(obj); + if (value is null) + { + break; + } + } + else + { + value = null; + break; + } + } + } + else + { + var bindingProperty = typeFrom.GetProperty(customAttribute.PropertyNameFromModel); + if (bindingProperty != null) + { + value = bindingProperty.GetValue(obj); + } + } + if (value is null) + { + continue; + } + property.SetValue(newObject, value); + } + } + + return newObject; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/BusinessLogics/ServiceProviderLoader.cs b/DepartmentPortal/Common/ModelTools/BusinessLogics/ServiceProviderLoader.cs new file mode 100644 index 0000000..9386353 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/BusinessLogics/ServiceProviderLoader.cs @@ -0,0 +1,79 @@ +using ModelTools.Extensions; +using ModelTools.Interfaces; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml.XPath; + +namespace ModelTools.BusinessLogics +{ + /// + /// Загрузчик данных + /// + public static class ServiceProviderLoader + { + private static readonly string _configFileName = "DepartmentPortal.config"; + + private static readonly string _pathToLoaderExt = "..\\..\\..\\..\\Extensions\\"; + + /// + /// Получение данных с файла настроек + /// + /// + /// + public static string GetConfigData(string key) + { + var fileName = GetFile(_configFileName); + if (!File.Exists(fileName)) + { + return string.Empty; + } + + var doc = new XPathDocument(fileName); + var nav = doc.CreateNavigator(); + var data = nav.SelectDescendants(key, "", false); + data.MoveNext(); + return data.Current.Value; + } + + /// + /// Загрузка всех классов-реализаций ILoaderExtensions + /// + /// + public static List GetLoaderExtensions() + { + var list = new List(); + if(Directory.Exists(_pathToLoaderExt)) + { + var files = Directory.GetFiles(_pathToLoaderExt, "*.dll", SearchOption.AllDirectories); + var loadedFiles = new List(); + foreach(var file in files.Distinct()) + { + if(loadedFiles.Contains(file.GetFileName())) + { + continue; + } + Assembly asm = Assembly.LoadFrom(file); + foreach (var t in asm.GetExportedTypes()) + { + if (t.IsClass && typeof(ILoaderExtensions).IsAssignableFrom(t)) + { + list.Add((ILoaderExtensions)Activator.CreateInstance(t)); + } + } + loadedFiles.Add(file.GetFileName()); + } + } + return list; + } + + /// + /// Получение имени файла + /// + /// + /// + private static string GetFile(string fileName) => Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), fileName); + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/BusinessLogics/UnityContainerConfigurator.cs b/DepartmentPortal/Common/ModelTools/BusinessLogics/UnityContainerConfigurator.cs new file mode 100644 index 0000000..4c03192 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/BusinessLogics/UnityContainerConfigurator.cs @@ -0,0 +1,43 @@ +using System; +using Unity; +using Unity.Lifetime; + +namespace ModelTools.BusinessLogics +{ + public class UnityContainerConfigurator + { + private static IUnityContainer _unityContainer; + + public static IUnityContainer Container + { + get + { + if (_unityContainer == null) _unityContainer = new UnityContainer(); + return _unityContainer; + } + } + + /// + /// Инициализация сервисов + /// + public static void InitServices() + { + var ext = ServiceProviderLoader.GetLoaderExtensions(); + if (ext.Count == 0) + { + throw new ArgumentNullException("Отсутствуют компоненты для загрузки зависимостей по модулям"); + } + // регистрируем в UnityContainaer зависимости + foreach (var e in ext) + { + e.RegisterServices(); + } + } + + public static void PublishService() where U : T => Container.RegisterType(new HierarchicalLifetimeManager()); + + public static void PublishService() => Container.RegisterType(new HierarchicalLifetimeManager()); + + public static T Resolve() => Container.Resolve(); + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Enums/AccessOperation.cs b/DepartmentPortal/Common/ModelTools/Enums/AccessOperation.cs new file mode 100644 index 0000000..67a70f6 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Enums/AccessOperation.cs @@ -0,0 +1,100 @@ +namespace ModelTools.Enums +{ + /// + /// Операции в системе + /// + public enum AccessOperation + { + #region Администрирование + Администрирование = 0, + + Роли = 1, + + Доступы = 2, + + Пользователи = 3, + + НастройкиСреды = 4, + #endregion + + #region База + Кафедра = 100, + + Аудитории = 101, + + Направления = 102, + + Преподаватели = 103, // + должности, звания + + Дисциплины = 104, // + Блоки дисциплин + + Группы = 105, // + + Студенты = 106, + + Приказы_студентов = 107, + #endregion + + // Меню Учебный процесс + Учебный_процесс = 150, + + Учебные_планы = 120, + + Виды_нагрузок = 121, + + Учебные_года = 122, + + Даты_семестра = 126, + + Контингент = 123, + + Нормы_времени = 124, + + Расчет_штатов = 125, + + Расчасовки = 127, + + Преподавательская_ставка = 128, + + Индивидуальный_план = 130, + + // Меню Расписание + Расписание = 200, + + Расписание_аудитории = 201, + + Расписание_группы = 202, + + Расписание_преподаватели = 203, + + Расписание_настройки = 204, + + Расписание_интервалы_пар = 205, + + Расписание_дисциплины = 206, + + // Меню Сервис + Сервис = 300, + + Генерация_билетов = 301, + + // Меню зав лаб + ЗавЛабораторией = 400, + + МатериальноТехническиеЦенности = 401, + + УстановленоеПО = 402, + + // Экзамены - составление билетов и проведение + СоставлениеЭкзаменов = 500, + + Ведомости = 501, + + ШаблоныБилетов = 502, + + // Web-портал + Новости = 600, + + Комментарии = 601 + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Enums/AccessType.cs b/DepartmentPortal/Common/ModelTools/Enums/AccessType.cs new file mode 100644 index 0000000..d6f0f00 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Enums/AccessType.cs @@ -0,0 +1,34 @@ +namespace ModelTools.Enums +{ + /// + /// Тип операции + /// + public enum AccessType : int + { + /// + /// Простой просомтр + /// + SimpleView = 0, + + /// + /// Полный просомтр + /// + FullView = 1, + + /// + /// Добавление/Изменение + /// + Change = 2, + + /// + /// Удаление + /// + Delete = 4, + + // TODO убрать + /// + /// Доступ к админке + /// + Administrator = 8 + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Enums/ResultServiceStatusCode.cs b/DepartmentPortal/Common/ModelTools/Enums/ResultServiceStatusCode.cs new file mode 100644 index 0000000..d31bf2d --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Enums/ResultServiceStatusCode.cs @@ -0,0 +1,38 @@ +namespace ModelTools.Enums +{ + /// + /// Статус результата операции + /// + public enum ResultServiceStatusCode + { + /// + /// Успешно + /// + Success = 200, + + /// + /// Ошибка общая + /// + Error = 400, + + /// + /// Элемент уже сущствует + /// + ExsistItem = 401, + + /// + /// Запись удалена + /// + WasDelete = 402, + + /// + /// Не найдено + /// + NotFound = 404, + + /// + /// Не найден файл + /// + FileNotFound = 405 + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Extensions/StringExtension.cs b/DepartmentPortal/Common/ModelTools/Extensions/StringExtension.cs new file mode 100644 index 0000000..b656bfd --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Extensions/StringExtension.cs @@ -0,0 +1,28 @@ +using System.IO; + +namespace ModelTools.Extensions +{ + public static class StringExtension + { + /// + /// Проверка, что строка пустая + /// + /// + /// + public static bool IsEmpty(this string str) => string.IsNullOrEmpty(str); + + /// + /// Проверка, что строка не пустая + /// + /// + /// + public static bool IsNotEmpty(this string str) => !string.IsNullOrEmpty(str); + + /// + /// Получение имени файла по полному пути + /// + /// + /// + public static string GetFileName(this string str) => (new FileInfo(str)).Name; + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Interfaces/IEntityService.cs b/DepartmentPortal/Common/ModelTools/Interfaces/IEntityService.cs new file mode 100644 index 0000000..2ab6242 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Interfaces/IEntityService.cs @@ -0,0 +1,41 @@ +using ModelTools.BindingModels; +using ModelTools.OperationResultModels; + +namespace ModelTools.Interfaces +{ + /// + /// Описание логики для хранилища сущности + /// + public interface IEntityService + where G : GetBindingModel + where S : SetBindingModel + { + /// + /// Получение списка сущностей + /// + /// + /// + OperationResultModel Read(G model); + + /// + /// Создание новой сущности + /// + /// + /// + OperationResultModel Create(S model); + + /// + /// Изменение сущности + /// + /// + /// + OperationResultModel Update(S model); + + /// + /// Удаление сущности + /// + /// + /// + OperationResultModel Delete(G model); + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Interfaces/ILoaderExtensions.cs b/DepartmentPortal/Common/ModelTools/Interfaces/ILoaderExtensions.cs new file mode 100644 index 0000000..1316e47 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Interfaces/ILoaderExtensions.cs @@ -0,0 +1,13 @@ +namespace ModelTools.Interfaces +{ + /// + /// Интерфейс для регистрации зависомстей в модулях + /// + public interface ILoaderExtensions + { + /// + /// Регистрация сервисов + /// + public void RegisterServices(); + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/Interfaces/ISecurityManager.cs b/DepartmentPortal/Common/ModelTools/Interfaces/ISecurityManager.cs new file mode 100644 index 0000000..78156d4 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/Interfaces/ISecurityManager.cs @@ -0,0 +1,23 @@ +using ModelTools.BindingModels; +using ModelTools.Enums; + +namespace ModelTools.Interfaces +{ + public interface ISecurityManager + { + /// + /// Сообщение с причиной не получения доступа + /// + string ErrorMessage { get; set; } + + /// + /// Авторизация пользователя к операции + /// + /// Данные по пользователю + /// Операция, которую хотят выполнить + /// Тип операции + /// Для какой сущности + /// + bool CheckAccess(AccessBindingModel model, AccessOperation operation, AccessType type, string entity); + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/ModelTools.csproj b/DepartmentPortal/Common/ModelTools/ModelTools.csproj new file mode 100644 index 0000000..dfb11d9 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/ModelTools.csproj @@ -0,0 +1,11 @@ + + + + net5.0 + + + + + + + diff --git a/DepartmentPortal/Common/ModelTools/OperationResultModels/OperationResultModel.cs b/DepartmentPortal/Common/ModelTools/OperationResultModels/OperationResultModel.cs new file mode 100644 index 0000000..9036f76 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/OperationResultModels/OperationResultModel.cs @@ -0,0 +1,114 @@ +using ModelTools.Enums; +using System; +using System.Collections.Generic; + +namespace ModelTools.OperationResultModels +{ + /// + /// Результат любой операции + /// + public class OperationResultModel + { + /// + /// Успешность операции (количество ошибок = 0) + /// + public bool IsSucceeded => Errors.Count == 0; + + /// + /// Статус операции + /// + public ResultServiceStatusCode StatusCode { get; set; } + + /// + /// Спсиок ошибок + /// + public List<(string Title, string Message)> Errors { get; private set; } + + /// + /// Объект, получаемый по результатам операции + /// + public object Result { get; private set; } + + /// + /// Конструктор по умолчанию + /// + public OperationResultModel() + { + Errors = new List<(string Title, string Message)>(); + StatusCode = ResultServiceStatusCode.Success; + } + + /// + /// Успешно + /// + /// + /// + public static OperationResultModel Success(object obj) + { + return new OperationResultModel + { + Result = obj, + Errors = new List<(string Title, string Message)>(), + StatusCode = ResultServiceStatusCode.Success + }; + } + + /// + /// Добавление простой ошибки + /// + /// + /// + /// + public static OperationResultModel Error(string key, string value) => Error(key, value, ResultServiceStatusCode.Error); + + /// + /// Добавление простой ошибки со сменой статуса + /// + /// + /// + /// + /// + public static OperationResultModel Error(string key, string error, ResultServiceStatusCode statusCode) + { + var model = new OperationResultModel(); + model.Errors.Add((key, error)); + model.StatusCode = statusCode; + return model; + } + + /// + /// Добавление ошибки + /// + /// + /// + public static OperationResultModel Error(Exception error) => Error(error, ResultServiceStatusCode.Error); + + /// + /// Добавление ошибки + /// + /// + /// + /// + public static OperationResultModel Error(Exception error, ResultServiceStatusCode statusCode) => Error("Ошибка", error, statusCode); + + /// + /// Добавление ошибки (включая вложеннные) + /// + /// + /// + /// + /// + public static OperationResultModel Error(string key, Exception error, ResultServiceStatusCode statusCode) + { + var model = new OperationResultModel(); + model.Errors.Add((key, error.Message)); + while (error.InnerException != null) + { + error = error.InnerException; + model.Errors.Add(("Inner error:", error.Message)); + } + model.StatusCode = statusCode; + return model; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/ViewModels/ElementViewModel.cs b/DepartmentPortal/Common/ModelTools/ViewModels/ElementViewModel.cs new file mode 100644 index 0000000..dfe800e --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/ViewModels/ElementViewModel.cs @@ -0,0 +1,15 @@ +using ModelTools.Attributes; +using System; + +namespace ModelTools.ViewModels +{ + /// + /// Возвращаемая запись + /// + public class ElementViewModel + { + [ViewModelProperty("Идентификатор", useOnList: true, useOnElement: false, isHide: true)] + [MapConfiguration("Id")] + public Guid Id { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Common/ModelTools/ViewModels/ListViewModel.cs b/DepartmentPortal/Common/ModelTools/ViewModels/ListViewModel.cs new file mode 100644 index 0000000..f98f307 --- /dev/null +++ b/DepartmentPortal/Common/ModelTools/ViewModels/ListViewModel.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace ModelTools.ViewModels +{ + /// + /// Список возвращаемых значений + /// + /// + public class ListViewModel + where T : ElementViewModel + { + public int MaxCount { get; set; } + + public List List { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/DepartmentPortal.sln b/DepartmentPortal/DepartmentPortal.sln index 822b3d2..3c23c6f 100644 --- a/DepartmentPortal/DepartmentPortal.sln +++ b/DepartmentPortal/DepartmentPortal.sln @@ -5,7 +5,17 @@ VisualStudioVersion = 16.0.31112.23 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{6F154F8D-3437-45EE-9D89-02B96BDF3E8E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonTools", "Common\CommonTools\CommonTools.csproj", "{9E533D43-452A-40D6-852B-01E8391BBFF9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseCore", "Common\DatabaseCore\DatabaseCore.csproj", "{D4DAAEDE-A550-42BB-A50C-AD8FCB23D00A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModelTools", "Common\ModelTools\ModelTools.csproj", "{8BE3C29B-6E9F-4DFC-BAC3-14229D58616F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Security", "Security", "{7DA26C36-778E-4563-9AEC-966E26EA7B2A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SecurityBusinessLogic", "Security\SecurityBusinessLogic\SecurityBusinessLogic.csproj", "{D424B54F-AF26-4A39-8D2B-CF874F31DE42}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DepartmentPortalDesctop", "DepartmentPortalDesctop\DepartmentPortalDesctop.csproj", "{B6CE93CB-998F-4F2D-BE9E-6FDF37FDFD0E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SecurityImplementation", "Security\SecurityImplementation\SecurityImplementation.csproj", "{24D7BD00-EC45-4B98-92BB-C6FFB01F66ED}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,16 +23,35 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9E533D43-452A-40D6-852B-01E8391BBFF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9E533D43-452A-40D6-852B-01E8391BBFF9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9E533D43-452A-40D6-852B-01E8391BBFF9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9E533D43-452A-40D6-852B-01E8391BBFF9}.Release|Any CPU.Build.0 = Release|Any CPU + {D4DAAEDE-A550-42BB-A50C-AD8FCB23D00A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4DAAEDE-A550-42BB-A50C-AD8FCB23D00A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4DAAEDE-A550-42BB-A50C-AD8FCB23D00A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4DAAEDE-A550-42BB-A50C-AD8FCB23D00A}.Release|Any CPU.Build.0 = Release|Any CPU + {8BE3C29B-6E9F-4DFC-BAC3-14229D58616F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BE3C29B-6E9F-4DFC-BAC3-14229D58616F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BE3C29B-6E9F-4DFC-BAC3-14229D58616F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BE3C29B-6E9F-4DFC-BAC3-14229D58616F}.Release|Any CPU.Build.0 = Release|Any CPU + {D424B54F-AF26-4A39-8D2B-CF874F31DE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D424B54F-AF26-4A39-8D2B-CF874F31DE42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D424B54F-AF26-4A39-8D2B-CF874F31DE42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D424B54F-AF26-4A39-8D2B-CF874F31DE42}.Release|Any CPU.Build.0 = Release|Any CPU + {B6CE93CB-998F-4F2D-BE9E-6FDF37FDFD0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6CE93CB-998F-4F2D-BE9E-6FDF37FDFD0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6CE93CB-998F-4F2D-BE9E-6FDF37FDFD0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6CE93CB-998F-4F2D-BE9E-6FDF37FDFD0E}.Release|Any CPU.Build.0 = Release|Any CPU + {24D7BD00-EC45-4B98-92BB-C6FFB01F66ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {24D7BD00-EC45-4B98-92BB-C6FFB01F66ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {24D7BD00-EC45-4B98-92BB-C6FFB01F66ED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {24D7BD00-EC45-4B98-92BB-C6FFB01F66ED}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {9E533D43-452A-40D6-852B-01E8391BBFF9} = {6F154F8D-3437-45EE-9D89-02B96BDF3E8E} + {D4DAAEDE-A550-42BB-A50C-AD8FCB23D00A} = {6F154F8D-3437-45EE-9D89-02B96BDF3E8E} + {8BE3C29B-6E9F-4DFC-BAC3-14229D58616F} = {6F154F8D-3437-45EE-9D89-02B96BDF3E8E} + {D424B54F-AF26-4A39-8D2B-CF874F31DE42} = {7DA26C36-778E-4563-9AEC-966E26EA7B2A} + {24D7BD00-EC45-4B98-92BB-C6FFB01F66ED} = {7DA26C36-778E-4563-9AEC-966E26EA7B2A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FBA0CB49-EF2D-4538-9D00-FCEDA24879A9} diff --git a/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortal.config b/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortal.config new file mode 100644 index 0000000..0151204 --- /dev/null +++ b/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortal.config @@ -0,0 +1,4 @@ + + + Data Source=10.3.1.13\SQLEXPRESS;Initial Catalog=DepartmentDatabasePortal;persist security info=True;user id=sa;password=isadmin;MultipleActiveResultSets=True; + \ No newline at end of file diff --git a/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortalDesctop.csproj b/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortalDesctop.csproj new file mode 100644 index 0000000..9b4d650 --- /dev/null +++ b/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortalDesctop.csproj @@ -0,0 +1,27 @@ + + + + WinExe + net5.0-windows + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + Always + + + + \ No newline at end of file diff --git a/DepartmentPortal/DepartmentPortalDesctop/FormEnter.Designer.cs b/DepartmentPortal/DepartmentPortalDesctop/FormEnter.Designer.cs new file mode 100644 index 0000000..3a59812 --- /dev/null +++ b/DepartmentPortal/DepartmentPortalDesctop/FormEnter.Designer.cs @@ -0,0 +1,119 @@ + +namespace DepartmentPortalDesctop +{ + partial class FormEnter + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.labelLogin = new System.Windows.Forms.Label(); + this.textBoxLogin = new System.Windows.Forms.TextBox(); + this.labelPassword = new System.Windows.Forms.Label(); + this.textBoxPassword = new System.Windows.Forms.TextBox(); + this.buttonEnter = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // labelLogin + // + this.labelLogin.AutoSize = true; + this.labelLogin.Location = new System.Drawing.Point(12, 9); + this.labelLogin.Name = "labelLogin"; + this.labelLogin.Size = new System.Drawing.Size(44, 15); + this.labelLogin.TabIndex = 0; + this.labelLogin.Text = "Логин:"; + // + // textBoxLogin + // + this.textBoxLogin.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxLogin.Location = new System.Drawing.Point(70, 6); + this.textBoxLogin.Name = "textBoxLogin"; + this.textBoxLogin.Size = new System.Drawing.Size(242, 23); + this.textBoxLogin.TabIndex = 1; + // + // labelPassword + // + this.labelPassword.AutoSize = true; + this.labelPassword.Location = new System.Drawing.Point(12, 49); + this.labelPassword.Name = "labelPassword"; + this.labelPassword.Size = new System.Drawing.Size(52, 15); + this.labelPassword.TabIndex = 2; + this.labelPassword.Text = "Пароль:"; + // + // textBoxPassword + // + this.textBoxPassword.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxPassword.Location = new System.Drawing.Point(70, 46); + this.textBoxPassword.Name = "textBoxPassword"; + this.textBoxPassword.Size = new System.Drawing.Size(242, 23); + this.textBoxPassword.TabIndex = 3; + this.textBoxPassword.UseSystemPasswordChar = true; + // + // buttonEnter + // + this.buttonEnter.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.buttonEnter.Cursor = System.Windows.Forms.Cursors.Hand; + this.buttonEnter.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonEnter.Location = new System.Drawing.Point(88, 88); + this.buttonEnter.MinimumSize = new System.Drawing.Size(100, 30); + this.buttonEnter.Name = "buttonEnter"; + this.buttonEnter.Size = new System.Drawing.Size(167, 30); + this.buttonEnter.TabIndex = 4; + this.buttonEnter.Text = "Вход"; + this.buttonEnter.UseVisualStyleBackColor = true; + this.buttonEnter.Click += new System.EventHandler(this.ButtonEnter_Click); + // + // FormEnter + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(324, 131); + this.Controls.Add(this.buttonEnter); + this.Controls.Add(this.textBoxPassword); + this.Controls.Add(this.labelPassword); + this.Controls.Add(this.textBoxLogin); + this.Controls.Add(this.labelLogin); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FormEnter"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Вход в систему"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label labelLogin; + private System.Windows.Forms.TextBox textBoxLogin; + private System.Windows.Forms.Label labelPassword; + private System.Windows.Forms.TextBox textBoxPassword; + private System.Windows.Forms.Button buttonEnter; + } +} \ No newline at end of file diff --git a/DepartmentPortal/DepartmentPortalDesctop/FormEnter.cs b/DepartmentPortal/DepartmentPortalDesctop/FormEnter.cs new file mode 100644 index 0000000..acfb1b8 --- /dev/null +++ b/DepartmentPortal/DepartmentPortalDesctop/FormEnter.cs @@ -0,0 +1,32 @@ +using SecurityBusinessLogic.BusinessLogics; +using System; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace DepartmentPortalDesctop +{ + /// + /// Форма входа в систему + /// + public partial class FormEnter : Form + { + public FormEnter() + { + InitializeComponent(); + } + + private void ButtonEnter_Click(object sender, EventArgs e) + { + try + { + Task.WaitAll(Task.Run(async () => await UserManager.GetInstance.LoginAsync(textBoxLogin.Text, textBoxPassword.Text))); + DialogResult = DialogResult.OK; + Close(); + } + catch (Exception ex) + { + //ErrorMessanger.PrintErrorMessage("При аутентфикации возникла ошибка: ", new List> { new KeyValuePair("Аутентфикация", ex.Message) }); + } + } + } +} diff --git a/DepartmentPortal/DepartmentPortalDesctop/FormEnter.resx b/DepartmentPortal/DepartmentPortalDesctop/FormEnter.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/DepartmentPortal/DepartmentPortalDesctop/FormEnter.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DepartmentPortal/DepartmentPortalDesctop/FormMain.Designer.cs b/DepartmentPortal/DepartmentPortalDesctop/FormMain.Designer.cs new file mode 100644 index 0000000..39fe88e --- /dev/null +++ b/DepartmentPortal/DepartmentPortalDesctop/FormMain.Designer.cs @@ -0,0 +1,125 @@ + +namespace DepartmentPortalDesctop +{ + partial class FormMain + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.menuMain = new System.Windows.Forms.MenuStrip(); + this.panelControls = new System.Windows.Forms.Panel(); + this.listBoxControls = new System.Windows.Forms.ListBox(); + this.splitContainerMain = new System.Windows.Forms.SplitContainer(); + this.ButtonShowHideControlList = new System.Windows.Forms.Button(); + this.panelControls.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainerMain)).BeginInit(); + this.splitContainerMain.SuspendLayout(); + this.SuspendLayout(); + // + // menuMain + // + this.menuMain.Location = new System.Drawing.Point(0, 0); + this.menuMain.Name = "menuMain"; + this.menuMain.Size = new System.Drawing.Size(800, 24); + this.menuMain.TabIndex = 0; + this.menuMain.Text = "Главное меню"; + // + // panelControls + // + this.panelControls.Controls.Add(this.listBoxControls); + this.panelControls.Dock = System.Windows.Forms.DockStyle.Left; + this.panelControls.Location = new System.Drawing.Point(0, 24); + this.panelControls.Name = "panelControls"; + this.panelControls.Size = new System.Drawing.Size(191, 426); + this.panelControls.TabIndex = 1; + // + // listBoxControls + // + this.listBoxControls.Dock = System.Windows.Forms.DockStyle.Fill; + this.listBoxControls.FormattingEnabled = true; + this.listBoxControls.ItemHeight = 15; + this.listBoxControls.Location = new System.Drawing.Point(0, 0); + this.listBoxControls.Name = "listBoxControls"; + this.listBoxControls.Size = new System.Drawing.Size(191, 426); + this.listBoxControls.TabIndex = 0; + // + // splitContainerMain + // + this.splitContainerMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainerMain.Location = new System.Drawing.Point(216, 24); + this.splitContainerMain.Name = "splitContainerMain"; + this.splitContainerMain.Panel1MinSize = 100; + // + // splitContainerMain.Panel2 + // + this.splitContainerMain.Panel2.AutoScroll = true; + this.splitContainerMain.Size = new System.Drawing.Size(584, 426); + this.splitContainerMain.SplitterDistance = 295; + this.splitContainerMain.TabIndex = 2; + // + // ButtonShowHideControlList + // + this.ButtonShowHideControlList.Dock = System.Windows.Forms.DockStyle.Left; + this.ButtonShowHideControlList.Location = new System.Drawing.Point(191, 24); + this.ButtonShowHideControlList.Name = "ButtonShowHideControlList"; + this.ButtonShowHideControlList.Size = new System.Drawing.Size(25, 426); + this.ButtonShowHideControlList.TabIndex = 3; + this.ButtonShowHideControlList.Text = ">"; + this.ButtonShowHideControlList.UseVisualStyleBackColor = true; + this.ButtonShowHideControlList.Click += new System.EventHandler(this.ButtonShowHideControlList_Click); + // + // FormMain + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.splitContainerMain); + this.Controls.Add(this.ButtonShowHideControlList); + this.Controls.Add(this.panelControls); + this.Controls.Add(this.menuMain); + this.MainMenuStrip = this.menuMain; + this.Name = "FormMain"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Кафедральный портал"; + this.WindowState = System.Windows.Forms.FormWindowState.Maximized; + this.panelControls.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainerMain)).EndInit(); + this.splitContainerMain.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MenuStrip menuMain; + private System.Windows.Forms.Panel panelControls; + private System.Windows.Forms.ListBox listBoxControls; + private System.Windows.Forms.SplitContainer splitContainerMain; + private System.Windows.Forms.Button ButtonShowHideControlList; + } +} + diff --git a/DepartmentPortal/DepartmentPortalDesctop/FormMain.cs b/DepartmentPortal/DepartmentPortalDesctop/FormMain.cs new file mode 100644 index 0000000..86a3111 --- /dev/null +++ b/DepartmentPortal/DepartmentPortalDesctop/FormMain.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace DepartmentPortalDesctop +{ + public partial class FormMain : Form + { + private Dictionary controls; + public FormMain() + { + InitializeComponent(); + controls = new Dictionary(); + } + + private void ButtonShowHideControlList_Click(object sender, EventArgs e) + { + ButtonShowHideControlList.Text = panelControls.Visible ? ">" : "<"; + panelControls.Visible = !panelControls.Visible; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/DepartmentPortalDesctop/FormMain.resx b/DepartmentPortal/DepartmentPortalDesctop/FormMain.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/DepartmentPortal/DepartmentPortalDesctop/FormMain.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DepartmentPortal/DepartmentPortalDesctop/Program.cs b/DepartmentPortal/DepartmentPortalDesctop/Program.cs new file mode 100644 index 0000000..2f29dcd --- /dev/null +++ b/DepartmentPortal/DepartmentPortalDesctop/Program.cs @@ -0,0 +1,33 @@ +using DatabaseCore; +using ModelTools.BusinessLogics; +using ModelTools.Interfaces; +using SecurityBusinessLogic.BusinessLogics; +using System; +using System.Windows.Forms; + +namespace DepartmentPortalDesctop +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + UnityContainerConfigurator.PublishService(); + UnityContainerConfigurator.InitServices(); + + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + var form = new FormEnter(); + + if (form.ShowDialog() == DialogResult.OK && UserManager.GetInstance.IsAuth) + { + Application.Run(UnityContainerConfigurator.Resolve()); + } + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Extensions/net5.0/DatabaseCore.dll b/DepartmentPortal/Extensions/net5.0/DatabaseCore.dll new file mode 100644 index 0000000..c57f744 Binary files /dev/null and b/DepartmentPortal/Extensions/net5.0/DatabaseCore.dll differ diff --git a/DepartmentPortal/Extensions/net5.0/ModelTools.dll b/DepartmentPortal/Extensions/net5.0/ModelTools.dll new file mode 100644 index 0000000..f6de6c2 Binary files /dev/null and b/DepartmentPortal/Extensions/net5.0/ModelTools.dll differ diff --git a/DepartmentPortal/Extensions/net5.0/SecurityBusinessLogic.dll b/DepartmentPortal/Extensions/net5.0/SecurityBusinessLogic.dll new file mode 100644 index 0000000..522d2d8 Binary files /dev/null and b/DepartmentPortal/Extensions/net5.0/SecurityBusinessLogic.dll differ diff --git a/DepartmentPortal/Extensions/net5.0/SecurityImplementation.deps.json b/DepartmentPortal/Extensions/net5.0/SecurityImplementation.deps.json new file mode 100644 index 0000000..d56a467 --- /dev/null +++ b/DepartmentPortal/Extensions/net5.0/SecurityImplementation.deps.json @@ -0,0 +1,1782 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v5.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v5.0": { + "SecurityImplementation/1.0.0": { + "dependencies": { + "DatabaseCore": "1.0.0", + "SecurityBusinessLogic": "1.0.0" + }, + "runtime": { + "SecurityImplementation.dll": {} + } + }, + "Microsoft.CSharp/4.5.0": {}, + "Microsoft.Data.SqlClient/2.0.1": { + "dependencies": { + "Microsoft.Data.SqlClient.SNI.runtime": "2.0.1", + "Microsoft.Identity.Client": "4.14.0", + "Microsoft.IdentityModel.JsonWebTokens": "5.6.0", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0", + "Microsoft.Win32.Registry": "4.7.0", + "System.Configuration.ConfigurationManager": "4.7.0", + "System.Diagnostics.DiagnosticSource": "5.0.1", + "System.Runtime.Caching": "4.7.0", + "System.Security.Principal.Windows": "4.7.0", + "System.Text.Encoding.CodePages": "4.7.0" + }, + "runtime": { + "lib/netcoreapp3.1/Microsoft.Data.SqlClient.dll": { + "assemblyVersion": "2.0.20168.4", + "fileVersion": "2.0.20168.4" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp3.1/Microsoft.Data.SqlClient.dll": { + "rid": "unix", + "assetType": "runtime", + "assemblyVersion": "2.0.20168.4", + "fileVersion": "2.0.20168.4" + }, + "runtimes/win/lib/netcoreapp3.1/Microsoft.Data.SqlClient.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "2.0.20168.4", + "fileVersion": "2.0.20168.4" + } + } + }, + "Microsoft.Data.SqlClient.SNI.runtime/2.0.1": { + "runtimeTargets": { + "runtimes/win-arm/native/Microsoft.Data.SqlClient.SNI.dll": { + "rid": "win-arm", + "assetType": "native", + "fileVersion": "2.0.1.0" + }, + "runtimes/win-arm/native/Microsoft.Data.SqlClient.SNI.pdb": { + "rid": "win-arm", + "assetType": "native", + "fileVersion": "0.0.0.0" + }, + "runtimes/win-arm64/native/Microsoft.Data.SqlClient.SNI.dll": { + "rid": "win-arm64", + "assetType": "native", + "fileVersion": "2.0.1.0" + }, + "runtimes/win-arm64/native/Microsoft.Data.SqlClient.SNI.pdb": { + "rid": "win-arm64", + "assetType": "native", + "fileVersion": "0.0.0.0" + }, + "runtimes/win-x64/native/Microsoft.Data.SqlClient.SNI.dll": { + "rid": "win-x64", + "assetType": "native", + "fileVersion": "2.0.1.0" + }, + "runtimes/win-x64/native/Microsoft.Data.SqlClient.SNI.pdb": { + "rid": "win-x64", + "assetType": "native", + "fileVersion": "0.0.0.0" + }, + "runtimes/win-x86/native/Microsoft.Data.SqlClient.SNI.dll": { + "rid": "win-x86", + "assetType": "native", + "fileVersion": "2.0.1.0" + }, + "runtimes/win-x86/native/Microsoft.Data.SqlClient.SNI.pdb": { + "rid": "win-x86", + "assetType": "native", + "fileVersion": "0.0.0.0" + } + } + }, + "Microsoft.EntityFrameworkCore/5.0.4": { + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "5.0.4", + "Microsoft.EntityFrameworkCore.Analyzers": "5.0.4", + "Microsoft.Extensions.Caching.Memory": "5.0.0", + "Microsoft.Extensions.DependencyInjection": "5.0.1", + "Microsoft.Extensions.Logging": "5.0.0", + "System.Collections.Immutable": "5.0.0", + "System.ComponentModel.Annotations": "5.0.0", + "System.Diagnostics.DiagnosticSource": "5.0.1" + }, + "runtime": { + "lib/netstandard2.1/Microsoft.EntityFrameworkCore.dll": { + "assemblyVersion": "5.0.4.0", + "fileVersion": "5.0.421.11803" + } + } + }, + "Microsoft.EntityFrameworkCore.Abstractions/5.0.4": { + "runtime": { + "lib/netstandard2.1/Microsoft.EntityFrameworkCore.Abstractions.dll": { + "assemblyVersion": "5.0.4.0", + "fileVersion": "5.0.421.11803" + } + } + }, + "Microsoft.EntityFrameworkCore.Analyzers/5.0.4": {}, + "Microsoft.EntityFrameworkCore.Relational/5.0.4": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "5.0.4", + "Microsoft.Extensions.Configuration.Abstractions": "5.0.0" + }, + "runtime": { + "lib/netstandard2.1/Microsoft.EntityFrameworkCore.Relational.dll": { + "assemblyVersion": "5.0.4.0", + "fileVersion": "5.0.421.11803" + } + } + }, + "Microsoft.EntityFrameworkCore.SqlServer/5.0.4": { + "dependencies": { + "Microsoft.Data.SqlClient": "2.0.1", + "Microsoft.EntityFrameworkCore.Relational": "5.0.4" + }, + "runtime": { + "lib/netstandard2.1/Microsoft.EntityFrameworkCore.SqlServer.dll": { + "assemblyVersion": "5.0.4.0", + "fileVersion": "5.0.421.11803" + } + } + }, + "Microsoft.Extensions.Caching.Abstractions/5.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "5.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Caching.Abstractions.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" + } + } + }, + "Microsoft.Extensions.Caching.Memory/5.0.0": { + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "5.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0", + "Microsoft.Extensions.Logging.Abstractions": "5.0.0", + "Microsoft.Extensions.Options": "5.0.0", + "Microsoft.Extensions.Primitives": "5.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/5.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "5.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" + } + } + }, + "Microsoft.Extensions.DependencyInjection/5.0.1": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0" + }, + "runtime": { + "lib/net5.0/Microsoft.Extensions.DependencyInjection.dll": { + "assemblyVersion": "5.0.0.1", + "fileVersion": "5.0.120.57516" + } + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" + } + } + }, + "Microsoft.Extensions.Logging/5.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "5.0.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0", + "Microsoft.Extensions.Logging.Abstractions": "5.0.0", + "Microsoft.Extensions.Options": "5.0.0" + }, + "runtime": { + "lib/netstandard2.1/Microsoft.Extensions.Logging.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/5.0.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" + } + } + }, + "Microsoft.Extensions.Options/5.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0", + "Microsoft.Extensions.Primitives": "5.0.0" + }, + "runtime": { + "lib/net5.0/Microsoft.Extensions.Options.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" + } + } + }, + "Microsoft.Extensions.Primitives/5.0.0": { + "runtime": { + "lib/netcoreapp3.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" + } + } + }, + "Microsoft.Identity.Client/4.14.0": { + "dependencies": { + "Microsoft.CSharp": "4.5.0", + "System.ComponentModel.TypeConverter": "4.3.0", + "System.Net.NameResolution": "4.3.0", + "System.Private.Uri": "4.3.2", + "System.Runtime.Serialization.Formatters": "4.3.0", + "System.Runtime.Serialization.Json": "4.3.0", + "System.Runtime.Serialization.Primitives": "4.3.0", + "System.Security.SecureString": "4.3.0", + "System.Xml.XDocument": "4.3.0" + }, + "runtime": { + "lib/netcoreapp2.1/Microsoft.Identity.Client.dll": { + "assemblyVersion": "4.14.0.0", + "fileVersion": "4.14.0.0" + } + } + }, + "Microsoft.IdentityModel.JsonWebTokens/5.6.0": { + "dependencies": { + "Microsoft.IdentityModel.Tokens": "5.6.0", + "Newtonsoft.Json": "10.0.1" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.IdentityModel.JsonWebTokens.dll": { + "assemblyVersion": "5.6.0.0", + "fileVersion": "5.6.0.61018" + } + } + }, + "Microsoft.IdentityModel.Logging/5.6.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.IdentityModel.Logging.dll": { + "assemblyVersion": "5.6.0.0", + "fileVersion": "5.6.0.61018" + } + } + }, + "Microsoft.IdentityModel.Protocols/5.6.0": { + "dependencies": { + "Microsoft.IdentityModel.Logging": "5.6.0", + "Microsoft.IdentityModel.Tokens": "5.6.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.IdentityModel.Protocols.dll": { + "assemblyVersion": "5.6.0.0", + "fileVersion": "5.6.0.61018" + } + } + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect/5.6.0": { + "dependencies": { + "Microsoft.IdentityModel.Protocols": "5.6.0", + "Newtonsoft.Json": "10.0.1", + "System.IdentityModel.Tokens.Jwt": "5.6.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": { + "assemblyVersion": "5.6.0.0", + "fileVersion": "5.6.0.61018" + } + } + }, + "Microsoft.IdentityModel.Tokens/5.6.0": { + "dependencies": { + "Microsoft.IdentityModel.Logging": "5.6.0", + "Newtonsoft.Json": "10.0.1", + "System.Security.Cryptography.Cng": "4.5.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.IdentityModel.Tokens.dll": { + "assemblyVersion": "5.6.0.0", + "fileVersion": "5.6.0.61018" + } + } + }, + "Microsoft.NETCore.Platforms/3.1.0": {}, + "Microsoft.NETCore.Targets/1.1.3": {}, + "Microsoft.Win32.Registry/4.7.0": { + "dependencies": { + "System.Security.AccessControl": "4.7.0", + "System.Security.Principal.Windows": "4.7.0" + } + }, + "Microsoft.Win32.SystemEvents/4.7.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.SystemEvents.dll": { + "assemblyVersion": "4.0.2.0", + "fileVersion": "4.700.19.56404" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp3.0/Microsoft.Win32.SystemEvents.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "4.0.2.0", + "fileVersion": "4.700.19.56404" + } + } + }, + "Newtonsoft.Json/10.0.1": { + "dependencies": { + "Microsoft.CSharp": "4.5.0", + "System.Collections": "4.3.0", + "System.ComponentModel.TypeConverter": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Dynamic.Runtime": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Runtime.Serialization.Formatters": "4.3.0", + "System.Runtime.Serialization.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0", + "System.Xml.XDocument": "4.3.0", + "System.Xml.XmlDocument": "4.3.0" + }, + "runtime": { + "lib/netstandard1.3/Newtonsoft.Json.dll": { + "assemblyVersion": "10.0.0.0", + "fileVersion": "10.0.1.20720" + } + } + }, + "runtime.native.System/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3" + } + }, + "System.Collections/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Collections.Concurrent/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Collections.Immutable/5.0.0": {}, + "System.Collections.NonGeneric/4.3.0": { + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Collections.Specialized/4.3.0": { + "dependencies": { + "System.Collections.NonGeneric": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Extensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.ComponentModel/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.ComponentModel.Annotations/5.0.0": {}, + "System.ComponentModel.Primitives/4.3.0": { + "dependencies": { + "System.ComponentModel": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.ComponentModel.TypeConverter/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Collections.NonGeneric": "4.3.0", + "System.Collections.Specialized": "4.3.0", + "System.ComponentModel": "4.3.0", + "System.ComponentModel.Primitives": "4.3.0", + "System.Globalization": "4.3.0", + "System.Linq": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Configuration.ConfigurationManager/4.7.0": { + "dependencies": { + "System.Security.Cryptography.ProtectedData": "4.7.0", + "System.Security.Permissions": "4.7.0" + }, + "runtime": { + "lib/netstandard2.0/System.Configuration.ConfigurationManager.dll": { + "assemblyVersion": "4.0.3.0", + "fileVersion": "4.700.19.56404" + } + } + }, + "System.Diagnostics.Debug/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.DiagnosticSource/5.0.1": { + "runtime": { + "lib/net5.0/System.Diagnostics.DiagnosticSource.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.220.61120" + } + } + }, + "System.Diagnostics.Tools/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.Tracing/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Drawing.Common/4.7.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.Win32.SystemEvents": "4.7.0" + }, + "runtime": { + "lib/netstandard2.0/System.Drawing.Common.dll": { + "assemblyVersion": "4.0.0.1", + "fileVersion": "4.6.26919.2" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp3.0/System.Drawing.Common.dll": { + "rid": "unix", + "assetType": "runtime", + "assemblyVersion": "4.0.2.0", + "fileVersion": "4.700.19.56404" + }, + "runtimes/win/lib/netcoreapp3.0/System.Drawing.Common.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "4.0.2.0", + "fileVersion": "4.700.19.56404" + } + } + }, + "System.Dynamic.Runtime/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Globalization/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Extensions/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "System.IdentityModel.Tokens.Jwt/5.6.0": { + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "5.6.0", + "Microsoft.IdentityModel.Tokens": "5.6.0", + "Newtonsoft.Json": "10.0.1" + }, + "runtime": { + "lib/netstandard2.0/System.IdentityModel.Tokens.Jwt.dll": { + "assemblyVersion": "5.6.0.0", + "fileVersion": "5.6.0.61018" + } + } + }, + "System.IO/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.FileSystem/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.FileSystem.Primitives/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Linq/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Linq.Expressions/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Linq": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Emit.Lightweight": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Net.NameResolution/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Principal.Windows": "4.7.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, + "System.Net.Primitives/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.ObjectModel/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Private.DataContractSerialization/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Linq": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Emit.Lightweight": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Serialization.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0", + "System.Xml.XDocument": "4.3.0", + "System.Xml.XmlDocument": "4.3.0", + "System.Xml.XmlSerializer": "4.3.0" + } + }, + "System.Private.Uri/4.3.2": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3" + } + }, + "System.Reflection/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit/4.3.0": { + "dependencies": { + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.ILGeneration/4.3.0": { + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.Lightweight/4.3.0": { + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Extensions/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Primitives/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.TypeExtensions/4.3.0": { + "dependencies": { + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Resources.ResourceManager/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3" + } + }, + "System.Runtime.Caching/4.7.0": { + "dependencies": { + "System.Configuration.ConfigurationManager": "4.7.0" + }, + "runtime": { + "lib/netstandard2.0/System.Runtime.Caching.dll": { + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.700.19.56404" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/System.Runtime.Caching.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.700.19.56404" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/4.5.2": {}, + "System.Runtime.Extensions/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.Handles/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.InteropServices/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Runtime.Numerics/4.3.0": { + "dependencies": { + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Runtime.Serialization.Formatters/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Serialization.Primitives": "4.3.0" + } + }, + "System.Runtime.Serialization.Json/4.3.0": { + "dependencies": { + "System.IO": "4.3.0", + "System.Private.DataContractSerialization": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.Serialization.Primitives/4.3.0": { + "dependencies": { + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Security.AccessControl/4.7.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "System.Security.Principal.Windows": "4.7.0" + } + }, + "System.Security.Cryptography.Cng/4.5.0": {}, + "System.Security.Cryptography.Primitives/4.3.0": { + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Security.Cryptography.ProtectedData/4.7.0": { + "runtime": { + "lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll": { + "assemblyVersion": "4.0.5.0", + "fileVersion": "4.700.19.56404" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "4.0.5.0", + "fileVersion": "4.700.19.56404" + } + } + }, + "System.Security.Permissions/4.7.0": { + "dependencies": { + "System.Security.AccessControl": "4.7.0", + "System.Windows.Extensions": "4.7.0" + }, + "runtime": { + "lib/netcoreapp3.0/System.Security.Permissions.dll": { + "assemblyVersion": "4.0.3.0", + "fileVersion": "4.700.19.56404" + } + } + }, + "System.Security.Principal.Windows/4.7.0": {}, + "System.Security.SecureString/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Text.Encoding/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Text.Encoding.CodePages/4.7.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0" + } + }, + "System.Text.Encoding.Extensions/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Text.RegularExpressions/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Threading/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Tasks/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3", + "System.Runtime": "4.3.0" + } + }, + "System.Threading.Tasks.Extensions/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Windows.Extensions/4.7.0": { + "dependencies": { + "System.Drawing.Common": "4.7.0" + }, + "runtime": { + "lib/netcoreapp3.0/System.Windows.Extensions.dll": { + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.700.19.56404" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp3.0/System.Windows.Extensions.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "4.0.1.0", + "fileVersion": "4.700.19.56404" + } + } + }, + "System.Xml.ReaderWriter/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Tasks.Extensions": "4.3.0" + } + }, + "System.Xml.XDocument/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0" + } + }, + "System.Xml.XmlDocument/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0" + } + }, + "System.Xml.XmlSerializer/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Linq": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0", + "System.Xml.XmlDocument": "4.3.0" + } + }, + "Unity/5.11.10": { + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + }, + "runtime": { + "lib/netcoreapp3.0/Unity.Abstractions.dll": { + "assemblyVersion": "5.11.7.0", + "fileVersion": "5.11.7.0" + }, + "lib/netcoreapp3.0/Unity.Container.dll": { + "assemblyVersion": "5.11.11.0", + "fileVersion": "5.11.11.0" + } + } + }, + "DatabaseCore/1.0.0": { + "dependencies": { + "Microsoft.EntityFrameworkCore": "5.0.4", + "Microsoft.EntityFrameworkCore.SqlServer": "5.0.4", + "ModelTools": "1.0.0", + "SecurityBusinessLogic": "1.0.0" + }, + "runtime": { + "DatabaseCore.dll": {} + } + }, + "ModelTools/1.0.0": { + "dependencies": { + "Unity": "5.11.10" + }, + "runtime": { + "ModelTools.dll": {} + } + }, + "SecurityBusinessLogic/1.0.0": { + "dependencies": { + "ModelTools": "1.0.0" + }, + "runtime": { + "SecurityBusinessLogic.dll": {} + } + } + } + }, + "libraries": { + "SecurityImplementation/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Microsoft.CSharp/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kaj6Wb4qoMuH3HySFJhxwQfe8R/sJsNJnANrvv8WdFPMoNbKY5htfNscv+LHCu5ipz+49m2e+WQXpLXr9XYemQ==", + "path": "microsoft.csharp/4.5.0", + "hashPath": "microsoft.csharp.4.5.0.nupkg.sha512" + }, + "Microsoft.Data.SqlClient/2.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cff+ug/XZnGmX6DFgLY92t7G9W3i8r23w5Qnuby41l9rS+X+f7Y51hV5glvIrmsu3tIcnxbR+Z4CQ2zGhksIJw==", + "path": "microsoft.data.sqlclient/2.0.1", + "hashPath": "microsoft.data.sqlclient.2.0.1.nupkg.sha512" + }, + "Microsoft.Data.SqlClient.SNI.runtime/2.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-MalWSIMdwLZoNXxjmFmeRrFgaUXbEADkYNGm6HM33pculFv8gKt53s1Frs+kTfVPWMYjocd4gqwz92KrkcLfXA==", + "path": "microsoft.data.sqlclient.sni.runtime/2.0.1", + "hashPath": "microsoft.data.sqlclient.sni.runtime.2.0.1.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore/5.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-upRpXluUeONMYO+O3RU8G+ZZcrnDrnNVWg4eJmSfertTdw7Hc5tgIeg/O8+oBKqf+OvBrQKW0U3PI9yoTsuPYg==", + "path": "microsoft.entityframeworkcore/5.0.4", + "hashPath": "microsoft.entityframeworkcore.5.0.4.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Abstractions/5.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4y+y28SHjniLIqj7M7YNRO8khBnCBtkM6TJG8oX0wyEZuLum+3e9vqqna1naaV6Hi4BhXBHcD/sjhIfW1u0ZfQ==", + "path": "microsoft.entityframeworkcore.abstractions/5.0.4", + "hashPath": "microsoft.entityframeworkcore.abstractions.5.0.4.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Analyzers/5.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-z8OMwlXcUZJCArcDdhR0NRkmS0UyNg08l1LXPZCgYqjBeW8RvNXshH3H5ru/7IOVpyOfKrG5Q3nsgdD18OFG/g==", + "path": "microsoft.entityframeworkcore.analyzers/5.0.4", + "hashPath": "microsoft.entityframeworkcore.analyzers.5.0.4.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.Relational/5.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9Qa6SqX+hJZogo99bICsS6kgQ1C5RtEjPrsvQxjInVdY9QSWsXWIYfem0rv3wi+htwkJuMHVHGSaqG1oeAwe+w==", + "path": "microsoft.entityframeworkcore.relational/5.0.4", + "hashPath": "microsoft.entityframeworkcore.relational.5.0.4.nupkg.sha512" + }, + "Microsoft.EntityFrameworkCore.SqlServer/5.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-wFn6lYyezhTIWpEB85NYn0TmVs0GiTQBbgKxK4/BmeEXBoLdltOngosey1u9t1+c2xjxuis1V7fP3wcLVSf+jg==", + "path": "microsoft.entityframeworkcore.sqlserver/5.0.4", + "hashPath": "microsoft.entityframeworkcore.sqlserver.5.0.4.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Abstractions/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bu8As90/SBAouMZ6fJ+qRNo1X+KgHGrVueFhhYi+E5WqEhcnp2HoWRFnMzXQ6g4RdZbvPowFerSbKNH4Dtg5yg==", + "path": "microsoft.extensions.caching.abstractions/5.0.0", + "hashPath": "microsoft.extensions.caching.abstractions.5.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Caching.Memory/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/1qPCleFOkJe0O+xmFqCNLFYQZTJz965sVw8CUB/BQgsApBwzAUsL2BUkDvQW+geRUVTXUS9zLa0pBjC2VJ1gA==", + "path": "microsoft.extensions.caching.memory/5.0.0", + "hashPath": "microsoft.extensions.caching.memory.5.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ETjSBHMp3OAZ4HxGQYpwyGsD8Sw5FegQXphi0rpoGMT74S4+I2mm7XJEswwn59XAaKOzC15oDSOWEE8SzDCd6Q==", + "path": "microsoft.extensions.configuration.abstractions/5.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.5.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection/5.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-//mDNrYeiJ0eh/awFhDFJQzkRVra/njU5Y4fyK7X29g5HScrzbUkKOKlyTtygthcGFt4zNC8G5CFCjb/oizomA==", + "path": "microsoft.extensions.dependencyinjection/5.0.1", + "hashPath": "microsoft.extensions.dependencyinjection.5.0.1.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ORj7Zh81gC69TyvmcUm9tSzytcy8AVousi+IVRAI8nLieQjOFryRusSFh7+aLk16FN9pQNqJAiMd7BTKINK0kA==", + "path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-MgOwK6tPzB6YNH21wssJcw/2MKwee8b2gI7SllYfn6rvTpIrVvVS5HAjSU2vqSku1fwqRvWP0MdIi14qjd93Aw==", + "path": "microsoft.extensions.logging/5.0.0", + "hashPath": "microsoft.extensions.logging.5.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-NxP6ahFcBnnSfwNBi2KH2Oz8Xl5Sm2krjId/jRR3I7teFphwiUoUeZPwTNA21EX+5PtjqmyAvKaOeBXcJjcH/w==", + "path": "microsoft.extensions.logging.abstractions/5.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.5.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Options/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-CBvR92TCJ5uBIdd9/HzDSrxYak+0W/3+yxrNg8Qm6Bmrkh5L+nu6m3WeazQehcZ5q1/6dDA7J5YdQjim0165zg==", + "path": "microsoft.extensions.options/5.0.0", + "hashPath": "microsoft.extensions.options.5.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cI/VWn9G1fghXrNDagX9nYaaB/nokkZn0HYAawGaELQrl8InSezfe9OnfPZLcJq3esXxygh3hkq2c3qoV3SDyQ==", + "path": "microsoft.extensions.primitives/5.0.0", + "hashPath": "microsoft.extensions.primitives.5.0.0.nupkg.sha512" + }, + "Microsoft.Identity.Client/4.14.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Etqux6Zuuv1yEN4UwKbAn6EZv0Rooc+vM4N9z7gxmeT7dyoKlXIRN44DQPzD9LV1CW0KsTVqH+2B42p1NKqPlQ==", + "path": "microsoft.identity.client/4.14.0", + "hashPath": "microsoft.identity.client.4.14.0.nupkg.sha512" + }, + "Microsoft.IdentityModel.JsonWebTokens/5.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0q0U1W+gX1jmfmv7uU7GXFGB518atmSwucxsVwPGpuaGS3jwd2tUi+Gau+ezxR6oAFEBFKG9lz/fxRZzGMeDXg==", + "path": "microsoft.identitymodel.jsonwebtokens/5.6.0", + "hashPath": "microsoft.identitymodel.jsonwebtokens.5.6.0.nupkg.sha512" + }, + "Microsoft.IdentityModel.Logging/5.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-zEDrfEVW5x5w2hbTV94WwAcWvtue5hNTXYqoPh3ypF6U8csm09JazEYy+VPp2RtczkyMfcsvWY9Fea17e+isYQ==", + "path": "microsoft.identitymodel.logging/5.6.0", + "hashPath": "microsoft.identitymodel.logging.5.6.0.nupkg.sha512" + }, + "Microsoft.IdentityModel.Protocols/5.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ei7YqYx0pIFL6JjK8ZnPK0MXZRWUNHtJPUl3KqSvj9+2f5CMa6GRSEC+BMDHr17tP6yujYUg0IQOcKzmC7qN5g==", + "path": "microsoft.identitymodel.protocols/5.6.0", + "hashPath": "microsoft.identitymodel.protocols.5.6.0.nupkg.sha512" + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect/5.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yh3n+uXiwpBy/5+t67tYcmRxb9kwQdaKRyG/DNipRMF37bg5Jr0vENOo1BQz6OySMl5WIK544SzPjtr7/KkucA==", + "path": "microsoft.identitymodel.protocols.openidconnect/5.6.0", + "hashPath": "microsoft.identitymodel.protocols.openidconnect.5.6.0.nupkg.sha512" + }, + "Microsoft.IdentityModel.Tokens/5.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C3OqR3QfBQ7wcC7yAsdMQqay87OsV6yWPYG/Ai3n7dvmWIGkouQhXoVxRP0xz3cAFL4hxZBXyw4aLTC421PaMg==", + "path": "microsoft.identitymodel.tokens/5.6.0", + "hashPath": "microsoft.identitymodel.tokens.5.6.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-z7aeg8oHln2CuNulfhiLYxCVMPEwBl3rzicjvIX+4sUuCwvXw5oXQEtbiU2c0z4qYL5L3Kmx0mMA/+t/SbY67w==", + "path": "microsoft.netcore.platforms/3.1.0", + "hashPath": "microsoft.netcore.platforms.3.1.0.nupkg.sha512" + }, + "Microsoft.NETCore.Targets/1.1.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ==", + "path": "microsoft.netcore.targets/1.1.3", + "hashPath": "microsoft.netcore.targets.1.1.3.nupkg.sha512" + }, + "Microsoft.Win32.Registry/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KSrRMb5vNi0CWSGG1++id2ZOs/1QhRqROt+qgbEAdQuGjGrFcl4AOl4/exGPUYz2wUnU42nvJqon1T3U0kPXLA==", + "path": "microsoft.win32.registry/4.7.0", + "hashPath": "microsoft.win32.registry.4.7.0.nupkg.sha512" + }, + "Microsoft.Win32.SystemEvents/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-mtVirZr++rq+XCDITMUdnETD59XoeMxSpLRIII7JRI6Yj0LEDiO1pPn0ktlnIj12Ix8bfvQqQDMMIF9wC98oCA==", + "path": "microsoft.win32.systemevents/4.7.0", + "hashPath": "microsoft.win32.systemevents.4.7.0.nupkg.sha512" + }, + "Newtonsoft.Json/10.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ebWzW9j2nwxQeBo59As2TYn7nYr9BHicqqCwHOD1Vdo+50HBtLPuqdiCYJcLdTRknpYis/DSEOQz5KmZxwrIAg==", + "path": "newtonsoft.json/10.0.1", + "hashPath": "newtonsoft.json.10.0.1.nupkg.sha512" + }, + "runtime.native.System/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", + "path": "runtime.native.system/4.3.0", + "hashPath": "runtime.native.system.4.3.0.nupkg.sha512" + }, + "System.Collections/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "path": "system.collections/4.3.0", + "hashPath": "system.collections.4.3.0.nupkg.sha512" + }, + "System.Collections.Concurrent/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==", + "path": "system.collections.concurrent/4.3.0", + "hashPath": "system.collections.concurrent.4.3.0.nupkg.sha512" + }, + "System.Collections.Immutable/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==", + "path": "system.collections.immutable/5.0.0", + "hashPath": "system.collections.immutable.5.0.0.nupkg.sha512" + }, + "System.Collections.NonGeneric/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-prtjIEMhGUnQq6RnPEYLpFt8AtLbp9yq2zxOSrY7KJJZrw25Fi97IzBqY7iqssbM61Ek5b8f3MG/sG1N2sN5KA==", + "path": "system.collections.nongeneric/4.3.0", + "hashPath": "system.collections.nongeneric.4.3.0.nupkg.sha512" + }, + "System.Collections.Specialized/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Epx8PoVZR0iuOnJJDzp7pWvdfMMOAvpUo95pC4ScH2mJuXkKA2Y4aR3cG9qt2klHgSons1WFh4kcGW7cSXvrxg==", + "path": "system.collections.specialized/4.3.0", + "hashPath": "system.collections.specialized.4.3.0.nupkg.sha512" + }, + "System.ComponentModel/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VyGn1jGRZVfxnh8EdvDCi71v3bMXrsu8aYJOwoV7SNDLVhiEqwP86pPMyRGsDsxhXAm2b3o9OIqeETfN5qfezw==", + "path": "system.componentmodel/4.3.0", + "hashPath": "system.componentmodel.4.3.0.nupkg.sha512" + }, + "System.ComponentModel.Annotations/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==", + "path": "system.componentmodel.annotations/5.0.0", + "hashPath": "system.componentmodel.annotations.5.0.0.nupkg.sha512" + }, + "System.ComponentModel.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-j8GUkCpM8V4d4vhLIIoBLGey2Z5bCkMVNjEZseyAlm4n5arcsJOeI3zkUP+zvZgzsbLTYh4lYeP/ZD/gdIAPrw==", + "path": "system.componentmodel.primitives/4.3.0", + "hashPath": "system.componentmodel.primitives.4.3.0.nupkg.sha512" + }, + "System.ComponentModel.TypeConverter/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-16pQ6P+EdhcXzPiEK4kbA953Fu0MNG2ovxTZU81/qsCd1zPRsKc3uif5NgvllCY598k6bI0KUyKW8fanlfaDQg==", + "path": "system.componentmodel.typeconverter/4.3.0", + "hashPath": "system.componentmodel.typeconverter.4.3.0.nupkg.sha512" + }, + "System.Configuration.ConfigurationManager/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/anOTeSZCNNI2zDilogWrZ8pNqCmYbzGNexUnNhjW8k0sHqEZ2nHJBp147jBV3hGYswu5lINpNg1vxR7bnqvVA==", + "path": "system.configuration.configurationmanager/4.7.0", + "hashPath": "system.configuration.configurationmanager.4.7.0.nupkg.sha512" + }, + "System.Diagnostics.Debug/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", + "path": "system.diagnostics.debug/4.3.0", + "hashPath": "system.diagnostics.debug.4.3.0.nupkg.sha512" + }, + "System.Diagnostics.DiagnosticSource/5.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-uXQEYqav2V3zP6OwkOKtLv+qIi6z3m1hsGyKwXX7ZA7htT4shoVccGxnJ9kVRFPNAsi1ArZTq2oh7WOto6GbkQ==", + "path": "system.diagnostics.diagnosticsource/5.0.1", + "hashPath": "system.diagnostics.diagnosticsource.5.0.1.nupkg.sha512" + }, + "System.Diagnostics.Tools/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UUvkJfSYJMM6x527dJg2VyWPSRqIVB0Z7dbjHst1zmwTXz5CcXSYJFWRpuigfbO1Lf7yfZiIaEUesfnl/g5EyA==", + "path": "system.diagnostics.tools/4.3.0", + "hashPath": "system.diagnostics.tools.4.3.0.nupkg.sha512" + }, + "System.Diagnostics.Tracing/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==", + "path": "system.diagnostics.tracing/4.3.0", + "hashPath": "system.diagnostics.tracing.4.3.0.nupkg.sha512" + }, + "System.Drawing.Common/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-v+XbyYHaZjDfn0ENmJEV1VYLgGgCTx1gnfOBcppowbpOAriglYgGCvFCPr2EEZyBvXlpxbEsTwkOlInl107ahA==", + "path": "system.drawing.common/4.7.0", + "hashPath": "system.drawing.common.4.7.0.nupkg.sha512" + }, + "System.Dynamic.Runtime/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-SNVi1E/vfWUAs/WYKhE9+qlS6KqK0YVhnlT0HQtr8pMIA8YX3lwy3uPMownDwdYISBdmAF/2holEIldVp85Wag==", + "path": "system.dynamic.runtime/4.3.0", + "hashPath": "system.dynamic.runtime.4.3.0.nupkg.sha512" + }, + "System.Globalization/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "path": "system.globalization/4.3.0", + "hashPath": "system.globalization.4.3.0.nupkg.sha512" + }, + "System.Globalization.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==", + "path": "system.globalization.extensions/4.3.0", + "hashPath": "system.globalization.extensions.4.3.0.nupkg.sha512" + }, + "System.IdentityModel.Tokens.Jwt/5.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KMvPpX4exs2fe7Upq5zHMSR4yupc+jy8WG8yjucZL0XvT+r/T0hRvLIe9fP/SeN8/UVxFYBRAkRI5k1zbRGqmA==", + "path": "system.identitymodel.tokens.jwt/5.6.0", + "hashPath": "system.identitymodel.tokens.jwt.5.6.0.nupkg.sha512" + }, + "System.IO/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "path": "system.io/4.3.0", + "hashPath": "system.io.4.3.0.nupkg.sha512" + }, + "System.IO.FileSystem/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", + "path": "system.io.filesystem/4.3.0", + "hashPath": "system.io.filesystem.4.3.0.nupkg.sha512" + }, + "System.IO.FileSystem.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", + "path": "system.io.filesystem.primitives/4.3.0", + "hashPath": "system.io.filesystem.primitives.4.3.0.nupkg.sha512" + }, + "System.Linq/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", + "path": "system.linq/4.3.0", + "hashPath": "system.linq.4.3.0.nupkg.sha512" + }, + "System.Linq.Expressions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==", + "path": "system.linq.expressions/4.3.0", + "hashPath": "system.linq.expressions.4.3.0.nupkg.sha512" + }, + "System.Net.NameResolution/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AFYl08R7MrsrEjqpQWTZWBadqXyTzNDaWpMqyxhb0d6sGhV6xMDKueuBXlLL30gz+DIRY6MpdgnHWlCh5wmq9w==", + "path": "system.net.nameresolution/4.3.0", + "hashPath": "system.net.nameresolution.4.3.0.nupkg.sha512" + }, + "System.Net.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qOu+hDwFwoZPbzPvwut2qATe3ygjeQBDQj91xlsaqGFQUI5i4ZnZb8yyQuLGpDGivEPIt8EJkd1BVzVoP31FXA==", + "path": "system.net.primitives/4.3.0", + "hashPath": "system.net.primitives.4.3.0.nupkg.sha512" + }, + "System.ObjectModel/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==", + "path": "system.objectmodel/4.3.0", + "hashPath": "system.objectmodel.4.3.0.nupkg.sha512" + }, + "System.Private.DataContractSerialization/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yDaJ2x3mMmjdZEDB4IbezSnCsnjQ4BxinKhRAaP6kEgL6Bb6jANWphs5SzyD8imqeC/3FxgsuXT6ykkiH1uUmA==", + "path": "system.private.datacontractserialization/4.3.0", + "hashPath": "system.private.datacontractserialization.4.3.0.nupkg.sha512" + }, + "System.Private.Uri/4.3.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-o1+7RJnu3Ik3PazR7Z7tJhjPdE000Eq2KGLLWhqJJKXj04wrS8lwb1OFtDF9jzXXADhUuZNJZlPc98uwwqmpFA==", + "path": "system.private.uri/4.3.2", + "hashPath": "system.private.uri.4.3.2.nupkg.sha512" + }, + "System.Reflection/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "path": "system.reflection/4.3.0", + "hashPath": "system.reflection.4.3.0.nupkg.sha512" + }, + "System.Reflection.Emit/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==", + "path": "system.reflection.emit/4.3.0", + "hashPath": "system.reflection.emit.4.3.0.nupkg.sha512" + }, + "System.Reflection.Emit.ILGeneration/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", + "path": "system.reflection.emit.ilgeneration/4.3.0", + "hashPath": "system.reflection.emit.ilgeneration.4.3.0.nupkg.sha512" + }, + "System.Reflection.Emit.Lightweight/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", + "path": "system.reflection.emit.lightweight/4.3.0", + "hashPath": "system.reflection.emit.lightweight.4.3.0.nupkg.sha512" + }, + "System.Reflection.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", + "path": "system.reflection.extensions/4.3.0", + "hashPath": "system.reflection.extensions.4.3.0.nupkg.sha512" + }, + "System.Reflection.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "path": "system.reflection.primitives/4.3.0", + "hashPath": "system.reflection.primitives.4.3.0.nupkg.sha512" + }, + "System.Reflection.TypeExtensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==", + "path": "system.reflection.typeextensions/4.3.0", + "hashPath": "system.reflection.typeextensions.4.3.0.nupkg.sha512" + }, + "System.Resources.ResourceManager/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "path": "system.resources.resourcemanager/4.3.0", + "hashPath": "system.resources.resourcemanager.4.3.0.nupkg.sha512" + }, + "System.Runtime/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "path": "system.runtime/4.3.0", + "hashPath": "system.runtime.4.3.0.nupkg.sha512" + }, + "System.Runtime.Caching/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-NdvNRjTPxYvIEhXQszT9L9vJhdQoX6AQ0AlhjTU+5NqFQVuacJTfhPVAvtGWNA2OJCqRiR/okBcZgMwI6MqcZg==", + "path": "system.runtime.caching/4.7.0", + "hashPath": "system.runtime.caching.4.7.0.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/4.5.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-wprSFgext8cwqymChhrBLu62LMg/1u92bU+VOwyfBimSPVFXtsNqEWC92Pf9ofzJFlk4IHmJA75EDJn1b2goAQ==", + "path": "system.runtime.compilerservices.unsafe/4.5.2", + "hashPath": "system.runtime.compilerservices.unsafe.4.5.2.nupkg.sha512" + }, + "System.Runtime.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "path": "system.runtime.extensions/4.3.0", + "hashPath": "system.runtime.extensions.4.3.0.nupkg.sha512" + }, + "System.Runtime.Handles/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "path": "system.runtime.handles/4.3.0", + "hashPath": "system.runtime.handles.4.3.0.nupkg.sha512" + }, + "System.Runtime.InteropServices/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "path": "system.runtime.interopservices/4.3.0", + "hashPath": "system.runtime.interopservices.4.3.0.nupkg.sha512" + }, + "System.Runtime.Numerics/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==", + "path": "system.runtime.numerics/4.3.0", + "hashPath": "system.runtime.numerics.4.3.0.nupkg.sha512" + }, + "System.Runtime.Serialization.Formatters/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KT591AkTNFOTbhZlaeMVvfax3RqhH1EJlcwF50Wm7sfnBLuHiOeZRRKrr1ns3NESkM20KPZ5Ol/ueMq5vg4QoQ==", + "path": "system.runtime.serialization.formatters/4.3.0", + "hashPath": "system.runtime.serialization.formatters.4.3.0.nupkg.sha512" + }, + "System.Runtime.Serialization.Json/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-CpVfOH0M/uZ5PH+M9+Gu56K0j9lJw3M+PKRegTkcrY/stOIvRUeonggxNrfBYLA5WOHL2j15KNJuTuld3x4o9w==", + "path": "system.runtime.serialization.json/4.3.0", + "hashPath": "system.runtime.serialization.json.4.3.0.nupkg.sha512" + }, + "System.Runtime.Serialization.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Wz+0KOukJGAlXjtKr+5Xpuxf8+c8739RI1C+A2BoQZT+wMCCoMDDdO8/4IRHfaVINqL78GO8dW8G2lW/e45Mcw==", + "path": "system.runtime.serialization.primitives/4.3.0", + "hashPath": "system.runtime.serialization.primitives.4.3.0.nupkg.sha512" + }, + "System.Security.AccessControl/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", + "path": "system.security.accesscontrol/4.7.0", + "hashPath": "system.security.accesscontrol.4.7.0.nupkg.sha512" + }, + "System.Security.Cryptography.Cng/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-WG3r7EyjUe9CMPFSs6bty5doUqT+q9pbI80hlNzo2SkPkZ4VTuZkGWjpp77JB8+uaL4DFPRdBsAY+DX3dBK92A==", + "path": "system.security.cryptography.cng/4.5.0", + "hashPath": "system.security.cryptography.cng.4.5.0.nupkg.sha512" + }, + "System.Security.Cryptography.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==", + "path": "system.security.cryptography.primitives/4.3.0", + "hashPath": "system.security.cryptography.primitives.4.3.0.nupkg.sha512" + }, + "System.Security.Cryptography.ProtectedData/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ehYW0m9ptxpGWvE4zgqongBVWpSDU/JCFD4K7krxkQwSz/sFQjEXCUqpvencjy6DYDbn7Ig09R8GFffu8TtneQ==", + "path": "system.security.cryptography.protecteddata/4.7.0", + "hashPath": "system.security.cryptography.protecteddata.4.7.0.nupkg.sha512" + }, + "System.Security.Permissions/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dkOV6YYVBnYRa15/yv004eCGRBVADXw8qRbbNiCn/XpdJSUXkkUeIvdvFHkvnko4CdKMqG8yRHC4ox83LSlMsQ==", + "path": "system.security.permissions/4.7.0", + "hashPath": "system.security.permissions.4.7.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==", + "path": "system.security.principal.windows/4.7.0", + "hashPath": "system.security.principal.windows.4.7.0.nupkg.sha512" + }, + "System.Security.SecureString/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PnXp38O9q/2Oe4iZHMH60kinScv6QiiL2XH54Pj2t0Y6c2zKPEiAZsM/M3wBOHLNTBDFP0zfy13WN2M0qFz5jg==", + "path": "system.security.securestring/4.3.0", + "hashPath": "system.security.securestring.4.3.0.nupkg.sha512" + }, + "System.Text.Encoding/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "path": "system.text.encoding/4.3.0", + "hashPath": "system.text.encoding.4.3.0.nupkg.sha512" + }, + "System.Text.Encoding.CodePages/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-aeu4FlaUTemuT1qOd1MyU4T516QR4Fy+9yDbwWMPHOHy7U8FD6SgTzdZFO7gHcfAPHtECqInbwklVvUK4RHcNg==", + "path": "system.text.encoding.codepages/4.7.0", + "hashPath": "system.text.encoding.codepages.4.7.0.nupkg.sha512" + }, + "System.Text.Encoding.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==", + "path": "system.text.encoding.extensions/4.3.0", + "hashPath": "system.text.encoding.extensions.4.3.0.nupkg.sha512" + }, + "System.Text.RegularExpressions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-RpT2DA+L660cBt1FssIE9CAGpLFdFPuheB7pLpKpn6ZXNby7jDERe8Ua/Ne2xGiwLVG2JOqziiaVCGDon5sKFA==", + "path": "system.text.regularexpressions/4.3.0", + "hashPath": "system.text.regularexpressions.4.3.0.nupkg.sha512" + }, + "System.Threading/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "path": "system.threading/4.3.0", + "hashPath": "system.threading.4.3.0.nupkg.sha512" + }, + "System.Threading.Tasks/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "path": "system.threading.tasks/4.3.0", + "hashPath": "system.threading.tasks.4.3.0.nupkg.sha512" + }, + "System.Threading.Tasks.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-npvJkVKl5rKXrtl1Kkm6OhOUaYGEiF9wFbppFRWSMoApKzt2PiPHT2Bb8a5sAWxprvdOAtvaARS9QYMznEUtug==", + "path": "system.threading.tasks.extensions/4.3.0", + "hashPath": "system.threading.tasks.extensions.4.3.0.nupkg.sha512" + }, + "System.Windows.Extensions/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-CeWTdRNfRaSh0pm2gDTJFwVaXfTq6Xwv/sA887iwPTneW7oMtMlpvDIO+U60+3GWTB7Aom6oQwv5VZVUhQRdPQ==", + "path": "system.windows.extensions/4.7.0", + "hashPath": "system.windows.extensions.4.7.0.nupkg.sha512" + }, + "System.Xml.ReaderWriter/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-GrprA+Z0RUXaR4N7/eW71j1rgMnEnEVlgii49GZyAjTH7uliMnrOU3HNFBr6fEDBCJCIdlVNq9hHbaDR621XBA==", + "path": "system.xml.readerwriter/4.3.0", + "hashPath": "system.xml.readerwriter.4.3.0.nupkg.sha512" + }, + "System.Xml.XDocument/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5zJ0XDxAIg8iy+t4aMnQAu0MqVbqyvfoUVl1yDV61xdo3Vth45oA2FoY4pPkxYAH5f8ixpmTqXeEIya95x0aCQ==", + "path": "system.xml.xdocument/4.3.0", + "hashPath": "system.xml.xdocument.4.3.0.nupkg.sha512" + }, + "System.Xml.XmlDocument/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lJ8AxvkX7GQxpC6GFCeBj8ThYVyQczx2+f/cWHJU8tjS7YfI6Cv6bon70jVEgs2CiFbmmM8b9j1oZVx0dSI2Ww==", + "path": "system.xml.xmldocument/4.3.0", + "hashPath": "system.xml.xmldocument.4.3.0.nupkg.sha512" + }, + "System.Xml.XmlSerializer/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-MYoTCP7EZ98RrANESW05J5ZwskKDoN0AuZ06ZflnowE50LTpbR5yRg3tHckTVm5j/m47stuGgCrCHWePyHS70Q==", + "path": "system.xml.xmlserializer/4.3.0", + "hashPath": "system.xml.xmlserializer.4.3.0.nupkg.sha512" + }, + "Unity/5.11.10": { + "type": "package", + "serviceable": true, + "sha512": "sha512-B4+Ps3oqI78hJ+dAFsJhPkJT6qycsNExgLbtw7CEHSzKc2ac3YyUR8SHQ+ZyTwld/y5IbDx/aNOHnKE9Em1zWA==", + "path": "unity/5.11.10", + "hashPath": "unity.5.11.10.nupkg.sha512" + }, + "DatabaseCore/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "ModelTools/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "SecurityBusinessLogic/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Extensions/net5.0/SecurityImplementation.dll b/DepartmentPortal/Extensions/net5.0/SecurityImplementation.dll new file mode 100644 index 0000000..1af8b4b Binary files /dev/null and b/DepartmentPortal/Extensions/net5.0/SecurityImplementation.dll differ diff --git a/DepartmentPortal/Extensions/net5.0/ref/SecurityImplementation.dll b/DepartmentPortal/Extensions/net5.0/ref/SecurityImplementation.dll new file mode 100644 index 0000000..4beadf6 Binary files /dev/null and b/DepartmentPortal/Extensions/net5.0/ref/SecurityImplementation.dll differ diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/AccessBindingModels.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/AccessBindingModels.cs new file mode 100644 index 0000000..4a14227 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/AccessBindingModels.cs @@ -0,0 +1,28 @@ +using ModelTools.BindingModels; +using ModelTools.Enums; +using System; +using System.ComponentModel.DataAnnotations; + +namespace SecurityBusinessLogic.BindingModels +{ + /// + /// Получение информации по доступу + /// + public class AccessGetBindingModel : GetBindingModel + { + public Guid? RoleId { get; set; } + } + + /// + /// Сохранение информации по доступу + /// + public class AccessSetBindingModel : SetBindingModel + { + public Guid RoleId { get; set; } + + [Required(ErrorMessage = "required")] + public AccessOperation Operation { get; set; } + + public AccessType AccessType { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/EnviromentSettingBindingModels.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/EnviromentSettingBindingModels.cs new file mode 100644 index 0000000..e672f6f --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/EnviromentSettingBindingModels.cs @@ -0,0 +1,25 @@ +using ModelTools.BindingModels; +using System.ComponentModel.DataAnnotations; + +namespace SecurityBusinessLogic.BindingModels +{ + /// + /// Получение общих настроек системы + /// + public class EnviromentSettingGetBindingModel : GetBindingModel + { + public string Key { get; set; } + } + + /// + /// Сохранение общих настроек системы + /// + public class EnviromentSettingSetBindingModel : SetBindingModel + { + [Required(ErrorMessage = "required")] + public string Key { get; set; } + + [Required(ErrorMessage = "required")] + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/RoleBindingModels.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/RoleBindingModels.cs new file mode 100644 index 0000000..2cbbc29 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/RoleBindingModels.cs @@ -0,0 +1,22 @@ +using ModelTools.BindingModels; +using System.ComponentModel.DataAnnotations; + +namespace SecurityBusinessLogic.BindingModels +{ + /// + /// Получение роли + /// + public class RoleGetBindingModel : GetBindingModel { } + + /// + /// Сохранение роли + /// + public class RoleSetBindingModel : SetBindingModel + { + [Required(ErrorMessage = "required")] + public string RoleName { get; set; } + + [Required(ErrorMessage = "required")] + public int RolePriority { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/UserBindingModels.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/UserBindingModels.cs new file mode 100644 index 0000000..daf0b13 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/UserBindingModels.cs @@ -0,0 +1,49 @@ +using ModelTools.BindingModels; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace SecurityBusinessLogic.BindingModels +{ + /// + /// Получение пользователя + /// + public class UserGetBindingModel : GetBindingModel + { + public bool? IsBanned { get; set; } + + public string Login { get; set; } + + public string Password { get; set; } + + public List LecturerIds { get; set; } + } + + /// + /// Сохранение пользователя + /// + public class UserSetBindingModel : SetBindingModel + { + [Required(ErrorMessage = "required")] + public string Login { get; set; } + + [Required(ErrorMessage = "required")] + public string Password { get; set; } + + public Guid? StudentId { get; set; } + + public Guid? LecturerId { get; set; } + + public Guid? EmployeeId { get; set; } + + public byte[] Avatar { get; set; } + + public DateTime? DateLastVisit { get; set; } + + public bool IsBanned { get; set; } + + public DateTime? DateBanned { get; set; } + + public int CountAttempt { get; set; } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/AccessBusinessLogic.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/AccessBusinessLogic.cs new file mode 100644 index 0000000..0c7cfec --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/AccessBusinessLogic.cs @@ -0,0 +1,21 @@ +using ModelTools.BusinessLogics; +using ModelTools.Enums; +using ModelTools.OperationResultModels; +using SecurityBusinessLogic.BindingModels; +using SecurityBusinessLogic.Interfaces; +using SecurityBusinessLogic.ViewModels; + +namespace SecurityBusinessLogic.BusinessLogics +{ + /// + /// Логика работы с доступами + /// + public class AccessBusinessLogic : BusinessLogicCore + { + public AccessBusinessLogic(IAccessService service) : base(service, "Доступы", AccessOperation.Доступы) { } + + protected override AccessViewModel ConvertToE(OperationResultModel model) => model.Result as AccessViewModel; + + protected override AccessListViewModel ConvertToL(OperationResultModel model) => model.Result as AccessListViewModel; + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/EnviromentSettingBusinessLogic.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/EnviromentSettingBusinessLogic.cs new file mode 100644 index 0000000..7f54e26 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/EnviromentSettingBusinessLogic.cs @@ -0,0 +1,22 @@ +using ModelTools.BusinessLogics; +using ModelTools.Enums; +using ModelTools.OperationResultModels; +using SecurityBusinessLogic.BindingModels; +using SecurityBusinessLogic.Interfaces; +using SecurityBusinessLogic.ViewModels; + +namespace SecurityBusinessLogic.BusinessLogics +{ + /// + /// Логика работы с общими настройками системы + /// + public class EnviromentSettingBusinessLogic : BusinessLogicCore + { + public EnviromentSettingBusinessLogic(IEnviromentSettingService service) : base(service, "Настройки Среды", AccessOperation.НастройкиСреды) { } + + protected override EnviromentSettingViewModel ConvertToE(OperationResultModel model) => model.Result as EnviromentSettingViewModel; + + protected override EnviromentSettingListViewModel ConvertToL(OperationResultModel model) => model.Result as EnviromentSettingListViewModel; + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/RoleBusinessLogic.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/RoleBusinessLogic.cs new file mode 100644 index 0000000..26a4e15 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/RoleBusinessLogic.cs @@ -0,0 +1,21 @@ +using ModelTools.BusinessLogics; +using ModelTools.Enums; +using ModelTools.OperationResultModels; +using SecurityBusinessLogic.BindingModels; +using SecurityBusinessLogic.Interfaces; +using SecurityBusinessLogic.ViewModels; + +namespace SecurityBusinessLogic.BusinessLogics +{ + /// + /// Логика работы с ролями + /// + public class RoleBusinessLogic : BusinessLogicCore + { + public RoleBusinessLogic(IRoleService service) : base(service, "Роли", AccessOperation.Роли) { } + + protected override RoleViewModel ConvertToE(OperationResultModel model) => model.Result as RoleViewModel; + + protected override RoleListViewModel ConvertToL(OperationResultModel model) => model.Result as RoleListViewModel; + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/UserBusinessLogic.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/UserBusinessLogic.cs new file mode 100644 index 0000000..ff84eaf --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/UserBusinessLogic.cs @@ -0,0 +1,21 @@ +using ModelTools.BusinessLogics; +using ModelTools.Enums; +using ModelTools.OperationResultModels; +using SecurityBusinessLogic.BindingModels; +using SecurityBusinessLogic.Interfaces; +using SecurityBusinessLogic.ViewModels; + +namespace SecurityBusinessLogic.BusinessLogics +{ + /// + /// Логика работы с пользователями + /// + public class UserBusinessLogic : BusinessLogicCore + { + public UserBusinessLogic(IUserService service) : base(service, "Пользователи", AccessOperation.Пользователи) { } + + protected override UserViewModel ConvertToE(OperationResultModel model) => model.Result as UserViewModel; + + protected override UserListViewModel ConvertToL(OperationResultModel model) => model.Result as UserListViewModel; + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/UserManager.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/UserManager.cs new file mode 100644 index 0000000..491c729 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/UserManager.cs @@ -0,0 +1,223 @@ +using ModelTools.BusinessLogics; +using SecurityBusinessLogic.BindingModels; +using SecurityBusinessLogic.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace SecurityBusinessLogic.BusinessLogics +{ + /// + /// Менеджер по работе с пользователем системы + /// + public class UserManager + { + private readonly int _countDayToBanned = 3; + + private readonly int _countMaxAttempt = 3; + + private readonly RoleBusinessLogic _roleBusinessLogic; + + private readonly UserBusinessLogic _userBusinessLogic; + + private static UserManager _userManager; + + private static readonly object _lockObject = new(); + + private UserManager() + { + _roleBusinessLogic = UnityContainerConfigurator.Resolve(); + _userBusinessLogic = UnityContainerConfigurator.Resolve(); + } + + public static UserManager GetInstance + { + get + { + if (_userManager == null) + { + lock (_lockObject) + { + _userManager = new UserManager(); + } + } + + return _userManager; + } + } + + /// + /// Аутентифицированный пользователь + /// + public UserViewModel User { get; private set; } + + /// + /// Список ролей аутентифицированного пользователь + /// + public List Roles { get; private set; } + + /// + /// Сообщение об ошибке + /// + public string ErrorMessage { get; private set; } + + /// + /// Идентификатор аутентифицированного пользователь + /// + public Guid? UserId => User?.Id; + + /// + /// Выполнена ли аутентификация + /// + public bool IsAuth => User != null; + + /// + /// Аутентификация пользователя + /// + /// + /// + /// + public async Task LoginAsync(string login, string password) + { + await Task.Run(() => + { + UserSetBindingModel model; + var passwordHash = GetPasswordHash(password); + var user = _userBusinessLogic.GetElement(new UserGetBindingModel + { + Login = login, + Password = passwordHash, + SkipCheck = true + }); + + if (user == null) + { + if(_userBusinessLogic.Errors.Count > 0) + { + throw new Exception(_userBusinessLogic.Errors[0].Message); + } + + user = _userBusinessLogic.GetElement(new UserGetBindingModel + { + Login = login, + IsBanned = true, + SkipCheck = true + }); + if (user != null) + { + user.CountAttempt++; + if (user.CountAttempt > _countMaxAttempt) + { + user.IsBanned = true; + user.DateBanned = DateTime.Now; + } + + model = GetSetBindingModel(user); + model.Password = passwordHash; + _userBusinessLogic.Update(model); + } + + if (_userBusinessLogic.Errors.Count > 0) + { + throw new Exception(_userBusinessLogic.Errors[0].Message); + } + + throw new Exception("Введен неверный логин/пароль"); + } + if (user.IsBanned) + { + if (user.DateBanned.Value.AddDays(_countDayToBanned) > DateTime.Now) + { + user.IsBanned = false; + } + else + { + throw new Exception("Пользователь заблокирован"); + } + } + + user.DateLastVisit = DateTime.Now; + user.CountAttempt = 0; + + model = GetSetBindingModel(user); + model.Password = passwordHash; + _userBusinessLogic.Update(model); + + User = user; + Roles = _roleBusinessLogic.GetList(new RoleGetBindingModel { UserId = User.Id }).List.Select(x => x.Id).ToList(); + }); + } + + /// + /// Выход из системы + /// + /// + public async Task LogoutAsync() + { + await Task.Run(() => + { + User = null; + Roles = null; + }); + } + + /// + /// Смена пароля + /// + /// + /// + /// + public void ChangePassword(string login, string oldPassword, string newPassword) + { + var user = _userBusinessLogic.GetElement(new UserGetBindingModel + { + Login = login, + Password = GetPasswordHash(oldPassword), + SkipCheck = true + }); + if (user == null) + { + throw new Exception("Введен неверный логин/пароль"); + } + if (user.IsBanned) + { + throw new Exception("Пользователь забаннен"); + } + var model = GetSetBindingModel(user); + model.Password = GetPasswordHash(newPassword); + _userBusinessLogic.Update(model); + } + + /// + /// Получение хеша пароля + /// + /// + /// + public static string GetPasswordHash(string password) => Encoding.ASCII.GetString((new MD5CryptoServiceProvider()).ComputeHash(Encoding.ASCII.GetBytes(password))); + + /// + /// Получение модели для сохранения из представления + /// + /// + /// + private static UserSetBindingModel GetSetBindingModel(UserViewModel model) + { + return new UserSetBindingModel + { + Id = model.Id, + Login = model.Login, + LecturerId = model.LecturerId, + StudentId = model.StudentId, + EmployeeId = model.EmployeeId, + Avatar = model.Avatar, + IsBanned = model.IsBanned, + DateBanned = model.DateBanned, + CountAttempt = model.CountAttempt, + DateLastVisit = model.DateLastVisit + }; + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IAccessService.cs b/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IAccessService.cs new file mode 100644 index 0000000..9d25010 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IAccessService.cs @@ -0,0 +1,10 @@ +using ModelTools.Interfaces; +using SecurityBusinessLogic.BindingModels; + +namespace SecurityBusinessLogic.Interfaces +{ + /// + /// Хранение доступов + /// + public interface IAccessService : IEntityService { } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IEnviromentSettingService.cs b/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IEnviromentSettingService.cs new file mode 100644 index 0000000..1c4fea5 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IEnviromentSettingService.cs @@ -0,0 +1,10 @@ +using ModelTools.Interfaces; +using SecurityBusinessLogic.BindingModels; + +namespace SecurityBusinessLogic.Interfaces +{ + /// + /// Хранение общих настроек системы + /// + public interface IEnviromentSettingService : IEntityService { } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IRoleService.cs b/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IRoleService.cs new file mode 100644 index 0000000..e65ce8c --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IRoleService.cs @@ -0,0 +1,10 @@ +using ModelTools.Interfaces; +using SecurityBusinessLogic.BindingModels; + +namespace SecurityBusinessLogic.Interfaces +{ + /// + /// Хранение ролей + /// + public interface IRoleService : IEntityService { } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IUserService.cs b/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IUserService.cs new file mode 100644 index 0000000..d62fdac --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/Interfaces/IUserService.cs @@ -0,0 +1,10 @@ +using ModelTools.Interfaces; +using SecurityBusinessLogic.BindingModels; + +namespace SecurityBusinessLogic.Interfaces +{ + /// + /// Хранение пользователей + /// + public interface IUserService : IEntityService { } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/SecurityBusinessLogic.csproj b/DepartmentPortal/Security/SecurityBusinessLogic/SecurityBusinessLogic.csproj new file mode 100644 index 0000000..eea8d8b --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/SecurityBusinessLogic.csproj @@ -0,0 +1,15 @@ + + + + net5.0 + + + + + + + + + + + diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/AccessViewModels.cs b/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/AccessViewModels.cs new file mode 100644 index 0000000..3ae3438 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/AccessViewModels.cs @@ -0,0 +1,42 @@ +using ModelTools.Attributes; +using ModelTools.Enums; +using ModelTools.ViewModels; +using System; + +namespace SecurityBusinessLogic.ViewModels +{ + /// + /// Список достпуов + /// + public class AccessListViewModel : ListViewModel { } + + /// + /// Элемент доступа + /// + public class AccessViewModel : ElementViewModel + { + [ViewModelProperty("Роль", false, true)] + [MapConfiguration("RoleId")] + public Guid RoleId { get; set; } + + [ViewModelProperty("Роль", true, false, 100)] + [MapConfiguration("Role.RoleName", true)] + public string RoleName { get; set; } + + [ViewModelProperty("Операция", false, true)] + [MapConfiguration("AccessOperation")] + public AccessOperation AccessOperation { get; set; } + + [ViewModelProperty("Операция", true, false)] + public string AccessOperationTitle => AccessOperation.ToString("G"); + + [ViewModelProperty("Тип", false, true)] + [MapConfiguration("AccessType")] + public AccessType AccessType { get; set; } + + [ViewModelProperty("Тип", true, false, 50)] + public string AccessTypeTitle => AccessType.ToString("G"); + + public override string ToString() => $"{RoleName}-{AccessOperationTitle}({AccessTypeTitle})"; + } +} diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/EnviromentSettingViewModels.cs b/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/EnviromentSettingViewModels.cs new file mode 100644 index 0000000..20d6262 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/EnviromentSettingViewModels.cs @@ -0,0 +1,26 @@ +using ModelTools.Attributes; +using ModelTools.ViewModels; + +namespace SecurityBusinessLogic.ViewModels +{ + /// + /// Список общих настроек системы + /// + public class EnviromentSettingListViewModel : ListViewModel { } + + /// + /// Элемент общих настроек системы + /// + public class EnviromentSettingViewModel : ElementViewModel + { + [ViewModelProperty("Ключ", true, true)] + [MapConfiguration("Key")] + public string Key { get; set; } + + [ViewModelProperty("Значение", true, true, 100)] + [MapConfiguration("Value")] + public int Value { get; set; } + + public override string ToString() => Key; + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/RoleViewModels.cs b/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/RoleViewModels.cs new file mode 100644 index 0000000..e55dad6 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/RoleViewModels.cs @@ -0,0 +1,26 @@ +using ModelTools.Attributes; +using ModelTools.ViewModels; + +namespace SecurityBusinessLogic.ViewModels +{ + /// + /// Список ролей + /// + public class RoleListViewModel : ListViewModel { } + + /// + /// Элемент ролей + /// + public class RoleViewModel : ElementViewModel + { + [ViewModelProperty("Название роли", true, true)] + [MapConfiguration("RoleName")] + public string RoleName { get; set; } + + [ViewModelProperty("Приоритет", true, true, 100)] + [MapConfiguration("RolePriority")] + public int RolePriority { get; set; } + + public override string ToString() => RoleName; + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/UserViewModels.cs b/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/UserViewModels.cs new file mode 100644 index 0000000..56c8933 --- /dev/null +++ b/DepartmentPortal/Security/SecurityBusinessLogic/ViewModels/UserViewModels.cs @@ -0,0 +1,62 @@ +using ModelTools.Attributes; +using ModelTools.ViewModels; +using System; + +namespace SecurityBusinessLogic.ViewModels +{ + /// + /// Список пользователей + /// + public class UserListViewModel : ListViewModel { } + + /// + /// Элемент пользователей + /// + public class UserViewModel : ElementViewModel + { + [ViewModelProperty("Пользователь", true, true)] + [MapConfiguration("UserName")] + public string Login { get; set; } + + [ViewModelProperty("Студент", false, true)] + [MapConfiguration("StudentId")] + public Guid? StudentId { get; set; } + + [ViewModelProperty("Преподаватель", false, true)] + [MapConfiguration("LecturerId")] + public Guid? LecturerId { get; set; } + + [ViewModelProperty("Сотрудник", false, true)] + [MapConfiguration("EmployeeId")] + public Guid? EmployeeId { get; set; } + + [ViewModelProperty("Фото", false, true)] + [MapConfiguration("Avatar")] + public byte[] Avatar { get; set; } + + [ViewModelProperty("Посл. визит", true, false, 100)] + [MapConfiguration("DateLastVisit")] + public DateTime? DateLastVisit { get; set; } + + [ViewModelProperty("Блокировка", false, true)] + [MapConfiguration("IsBanned")] + public bool IsBanned { get; set; } + + [ViewModelProperty("Блокир.", true, false, 100)] + public string Banned => IsBanned ? "Да" : "Нет"; + + [ViewModelProperty("Дата Б.", false, true, 100)] + [MapConfiguration("DateBanned")] + public DateTime? DateBanned { get; set; } + + [ViewModelProperty("Дата Б.", true, false, 100)] + public string DateBannedTitle => DateBanned.HasValue ? DateBanned.Value.ToShortDateString() : string.Empty; + + [ViewModelProperty("Количество попыток входа", false, false)] + [MapConfiguration("CountAttempt")] + public int CountAttempt { get; set; } + + public override string ToString() => Login; + + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityImplementation/Implementations/AccessService.cs b/DepartmentPortal/Security/SecurityImplementation/Implementations/AccessService.cs new file mode 100644 index 0000000..27caa61 --- /dev/null +++ b/DepartmentPortal/Security/SecurityImplementation/Implementations/AccessService.cs @@ -0,0 +1,131 @@ +using DatabaseCore; +using DatabaseCore.Models.Security; +using Microsoft.EntityFrameworkCore; +using ModelTools.BusinessLogics; +using ModelTools.Enums; +using ModelTools.OperationResultModels; +using SecurityBusinessLogic.BindingModels; +using SecurityBusinessLogic.Interfaces; +using SecurityBusinessLogic.ViewModels; +using System; +using System.Linq; + +namespace SecurityImplementation.Implementations +{ + /// + /// Реализация IAccessService + /// + public class AccessService : IAccessService + { + public OperationResultModel Create(AccessSetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var exsistEntity = context.Accesses.FirstOrDefault(x => x.Operation == model.Operation && x.RoleId == model.RoleId && x.AccessType == model.AccessType); + if (exsistEntity == null) + { + var entity = Mapper.MapToClass(model); + context.Accesses.Add(entity); + context.SaveChanges(); + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + else + { + if (exsistEntity.IsDeleted) + { + exsistEntity.IsDeleted = false; + context.SaveChanges(); + return OperationResultModel.Success(Mapper.MapToClass(exsistEntity)); + } + else + { + return OperationResultModel.Error("Error:", "Элемент уже существует", ResultServiceStatusCode.ExsistItem); + } + } + } + + public OperationResultModel Delete(AccessGetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var entity = context.Accesses.FirstOrDefault(x => x.Id == model.Id); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + else if (entity.IsDeleted) + { + return OperationResultModel.Error("Error:", "Элемент был удален", ResultServiceStatusCode.WasDelete); + } + entity.IsDeleted = true; + entity.DateDelete = DateTime.Now; + + context.SaveChanges(); + + return OperationResultModel.Success(true); + } + + public OperationResultModel Read(AccessGetBindingModel model) + { + int countPages = 0; + using var context = DatabaseManager.GetContext; + + // для одной записи + if(model.Id.HasValue) + { + var entity = context.Accesses.FirstOrDefault(x => x.Id == model.Id.Value); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + + var query = context.Accesses.Where(x => !x.IsDeleted).AsQueryable(); + if (model.RoleId.HasValue) + { + query = query.Where(x => x.RoleId == model.RoleId); + } + + query = query.OrderBy(x => x.Role.RoleName).ThenBy(x => x.Operation).ThenBy(x => x.AccessType); + + if (model.PageNumber.HasValue && model.PageSize.HasValue) + { + countPages = (int)Math.Ceiling((double)query.Count() / model.PageSize.Value); + query = query + .Skip(model.PageSize.Value * model.PageNumber.Value) + .Take(model.PageSize.Value); + } + + query = query.Include(x => x.Role); + + var result = new AccessListViewModel + { + MaxCount = countPages, + List = query.Select(Mapper.MapToClass).ToList() + }; + + return OperationResultModel.Success(result); + } + + public OperationResultModel Update(AccessSetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var entity = context.Accesses.FirstOrDefault(x => x.Id == model.Id); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + else if (entity.IsDeleted) + { + return OperationResultModel.Error("Error:", "Элемент был удален", ResultServiceStatusCode.WasDelete); + } + entity = Mapper.MapToClass(model, entity); + + context.SaveChanges(); + + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityImplementation/Implementations/EnviromentSettingService.cs b/DepartmentPortal/Security/SecurityImplementation/Implementations/EnviromentSettingService.cs new file mode 100644 index 0000000..01ea3d0 --- /dev/null +++ b/DepartmentPortal/Security/SecurityImplementation/Implementations/EnviromentSettingService.cs @@ -0,0 +1,114 @@ +using DatabaseCore; +using DatabaseCore.Models.Security; +using ModelTools.BusinessLogics; +using ModelTools.Enums; +using ModelTools.Extensions; +using ModelTools.OperationResultModels; +using SecurityBusinessLogic.BindingModels; +using SecurityBusinessLogic.Interfaces; +using SecurityBusinessLogic.ViewModels; +using System; +using System.Linq; + +namespace SecurityImplementation.Implementations +{ + /// + /// Реализация IEnviromentSettingService + /// + public class EnviromentSettingService : IEnviromentSettingService + { + public OperationResultModel Create(EnviromentSettingSetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var exsistEntity = context.EnviromentSettings.FirstOrDefault(x => x.Key == model.Key); + if (exsistEntity == null) + { + var entity = Mapper.MapToClass(model); + context.EnviromentSettings.Add(entity); + context.SaveChanges(); + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + return OperationResultModel.Error("Error:", "Элемент уже существует", ResultServiceStatusCode.ExsistItem); + } + + public OperationResultModel Delete(EnviromentSettingGetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var entity = context.EnviromentSettings.FirstOrDefault(x => x.Id == model.Id); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + + context.EnviromentSettings.Remove(entity); + context.SaveChanges(); + + return OperationResultModel.Success(true); + } + + public OperationResultModel Read(EnviromentSettingGetBindingModel model) + { + int countPages = 0; + using var context = DatabaseManager.GetContext; + + // для одной записи + if (model.Id.HasValue) + { + var entity = context.EnviromentSettings.FirstOrDefault(x => x.Id == model.Id.Value); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + + if (model.Key.IsNotEmpty()) + { + var entity = context.EnviromentSettings.FirstOrDefault(x => x.Key == model.Key); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + + var query = context.EnviromentSettings.AsQueryable(); + + query = query.OrderBy(x => x.Key); + + if (model.PageNumber.HasValue && model.PageSize.HasValue) + { + countPages = (int)Math.Ceiling((double)query.Count() / model.PageSize.Value); + query = query + .Skip(model.PageSize.Value * model.PageNumber.Value) + .Take(model.PageSize.Value); + } + + var result = new EnviromentSettingListViewModel + { + MaxCount = countPages, + List = query.Select(Mapper.MapToClass).ToList() + }; + + return OperationResultModel.Success(result); + } + + public OperationResultModel Update(EnviromentSettingSetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var entity = context.EnviromentSettings.FirstOrDefault(x => x.Id == model.Id); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + entity = Mapper.MapToClass(model, entity); + + context.SaveChanges(); + + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityImplementation/Implementations/RoleService.cs b/DepartmentPortal/Security/SecurityImplementation/Implementations/RoleService.cs new file mode 100644 index 0000000..80b19b4 --- /dev/null +++ b/DepartmentPortal/Security/SecurityImplementation/Implementations/RoleService.cs @@ -0,0 +1,150 @@ +using DatabaseCore; +using DatabaseCore.Models.Security; +using ModelTools.BusinessLogics; +using ModelTools.Enums; +using ModelTools.OperationResultModels; +using SecurityBusinessLogic.BindingModels; +using SecurityBusinessLogic.Interfaces; +using SecurityBusinessLogic.ViewModels; +using System; +using System.Linq; + +namespace SecurityImplementation.Implementations +{ + /// + /// Реализация IRoleService + /// + public class RoleService : IRoleService + { + public OperationResultModel Create(RoleSetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var exsistEntity = context.Roles.FirstOrDefault(x => x.RoleName == model.RoleName); + if (exsistEntity == null) + { + var entity = Mapper.MapToClass(model); + context.Roles.Add(entity); + context.SaveChanges(); + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + else + { + if (exsistEntity.IsDeleted) + { + exsistEntity.IsDeleted = false; + context.SaveChanges(); + return OperationResultModel.Success(Mapper.MapToClass(exsistEntity)); + } + else + { + return OperationResultModel.Error("Error:", "Элемент уже существует", ResultServiceStatusCode.ExsistItem); + } + } + } + + public OperationResultModel Delete(RoleGetBindingModel model) + { + using var context = DatabaseManager.GetContext; + using var transaction = context.Database.BeginTransaction(); + try + { + var entity = context.Roles.FirstOrDefault(x => x.Id == model.Id); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + else if (entity.IsDeleted) + { + return OperationResultModel.Error("Error:", "Элемент был удален", ResultServiceStatusCode.WasDelete); + } + entity.IsDeleted = true; + entity.DateDelete = DateTime.Now; + + context.SaveChanges(); + + var access = context.Accesses.Where(x => x.RoleId == model.Id); + foreach(var ac in access) + { + ac.IsDeleted = true; + ac.DateDelete = DateTime.Now; + } + context.SaveChanges(); + + var users = context.UserRoles.Where(x => x.RoleId == model.Id); + foreach (var u in users) + { + u.IsDeleted = true; + u.DateDelete = DateTime.Now; + } + context.SaveChanges(); + + transaction.Commit(); + } + catch(Exception) + { + transaction.Rollback(); + throw; + } + + return OperationResultModel.Success(true); + } + + public OperationResultModel Read(RoleGetBindingModel model) + { + int countPages = 0; + using var context = DatabaseManager.GetContext; + + // для одной записи + if (model.Id.HasValue) + { + var entity = context.Roles.FirstOrDefault(x => x.Id == model.Id.Value); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + + var query = context.Roles.Where(x => !x.IsDeleted).AsQueryable(); + + query = query.OrderBy(x => x.RoleName); + + if (model.PageNumber.HasValue && model.PageSize.HasValue) + { + countPages = (int)Math.Ceiling((double)query.Count() / model.PageSize.Value); + query = query + .Skip(model.PageSize.Value * model.PageNumber.Value) + .Take(model.PageSize.Value); + } + + var result = new RoleListViewModel + { + MaxCount = countPages, + List = query.Select(Mapper.MapToClass).ToList() + }; + + return OperationResultModel.Success(result); + } + + public OperationResultModel Update(RoleSetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var entity = context.Roles.FirstOrDefault(x => x.Id == model.Id); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + else if (entity.IsDeleted) + { + return OperationResultModel.Error("Error:", "Элемент был удален", ResultServiceStatusCode.WasDelete); + } + entity = Mapper.MapToClass(model, entity); + + context.SaveChanges(); + + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityImplementation/Implementations/UserService.cs b/DepartmentPortal/Security/SecurityImplementation/Implementations/UserService.cs new file mode 100644 index 0000000..142698c --- /dev/null +++ b/DepartmentPortal/Security/SecurityImplementation/Implementations/UserService.cs @@ -0,0 +1,171 @@ +using DatabaseCore; +using DatabaseCore.Models.Security; +using ModelTools.BusinessLogics; +using ModelTools.Enums; +using ModelTools.Extensions; +using ModelTools.OperationResultModels; +using SecurityBusinessLogic.BindingModels; +using SecurityBusinessLogic.Interfaces; +using SecurityBusinessLogic.ViewModels; +using System; +using System.Linq; + +namespace SecurityImplementation.Implementations +{ + /// + /// Реализация IUserService + /// + public class UserService : IUserService + { + public OperationResultModel Create(UserSetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var exsistEntity = context.Users.FirstOrDefault(x => x.UserName == model.Login); + if (exsistEntity == null) + { + var entity = Mapper.MapToClass(model); + context.Users.Add(entity); + context.SaveChanges(); + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + else + { + if (exsistEntity.IsDeleted) + { + exsistEntity.IsDeleted = false; + context.SaveChanges(); + return OperationResultModel.Success(Mapper.MapToClass(exsistEntity)); + } + else + { + return OperationResultModel.Error("Error:", "Элемент уже существует", ResultServiceStatusCode.ExsistItem); + } + } + } + + public OperationResultModel Delete(UserGetBindingModel model) + { + using var context = DatabaseManager.GetContext; + using var transaction = context.Database.BeginTransaction(); + try + { + var entity = context.Users.FirstOrDefault(x => x.Id == model.Id); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + else if (entity.IsDeleted) + { + return OperationResultModel.Error("Error:", "Элемент был удален", ResultServiceStatusCode.WasDelete); + } + entity.IsDeleted = true; + entity.DateDelete = DateTime.Now; + + context.SaveChanges(); + + var users = context.UserRoles.Where(x => x.UserId == model.Id); + foreach (var u in users) + { + u.IsDeleted = true; + u.DateDelete = DateTime.Now; + } + context.SaveChanges(); + + transaction.Commit(); + } + catch (Exception) + { + transaction.Rollback(); + throw; + } + + return OperationResultModel.Success(true); + } + + public OperationResultModel Read(UserGetBindingModel model) + { + int countPages = 0; + using var context = DatabaseManager.GetContext; + + // для одной записи + if (model.Id.HasValue) + { + var entity = context.Users.FirstOrDefault(x => x.Id == model.Id.Value); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + + if (model.Login.IsNotEmpty() && model.Password.IsNotEmpty()) + { + var entity = context.Users.FirstOrDefault(x => x.UserName == model.Login && x.PasswordHash == model.Password); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + + if (model.Login.IsNotEmpty() && model.IsBanned.HasValue) + { + var entity = context.Users.FirstOrDefault(x => x.UserName == model.Login && x.IsBanned == model.IsBanned.Value); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + + var query = context.Users.Where(x => !x.IsDeleted).AsQueryable(); + if (model.IsBanned.HasValue) + { + query = query.Where(x => x.IsBanned == model.IsBanned.Value); + } + if (model.LecturerIds != null) + { + query = query.Where(x => x.LecturerId.HasValue && model.LecturerIds.Contains(x.LecturerId.Value)); + } + + query = query.OrderBy(x => x.UserName); + + if (model.PageNumber.HasValue && model.PageSize.HasValue) + { + countPages = (int)Math.Ceiling((double)query.Count() / model.PageSize.Value); + query = query + .Skip(model.PageSize.Value * model.PageNumber.Value) + .Take(model.PageSize.Value); + } + + var result = new UserListViewModel + { + MaxCount = countPages, + List = query.Select(Mapper.MapToClass).ToList() + }; + + return OperationResultModel.Success(result); + } + + public OperationResultModel Update(UserSetBindingModel model) + { + using var context = DatabaseManager.GetContext; + + var entity = context.Users.FirstOrDefault(x => x.Id == model.Id); + if (entity == null) + { + return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound); + } + else if (entity.IsDeleted) + { + return OperationResultModel.Error("Error:", "Элемент был удален", ResultServiceStatusCode.WasDelete); + } + entity = Mapper.MapToClass(model, entity); + + context.SaveChanges(); + + return OperationResultModel.Success(Mapper.MapToClass(entity)); + } + } +} \ No newline at end of file diff --git a/DepartmentPortal/Security/SecurityImplementation/SecurityImplementation.csproj b/DepartmentPortal/Security/SecurityImplementation/SecurityImplementation.csproj new file mode 100644 index 0000000..d808588 --- /dev/null +++ b/DepartmentPortal/Security/SecurityImplementation/SecurityImplementation.csproj @@ -0,0 +1,16 @@ + + + + net5.0 + + + + ..\..\Extensions\ + + + + + + + + diff --git a/DepartmentPortal/Security/SecurityImplementation/SecurityLoaderExtensions.cs b/DepartmentPortal/Security/SecurityImplementation/SecurityLoaderExtensions.cs new file mode 100644 index 0000000..b9767c4 --- /dev/null +++ b/DepartmentPortal/Security/SecurityImplementation/SecurityLoaderExtensions.cs @@ -0,0 +1,24 @@ +using ModelTools.BusinessLogics; +using ModelTools.Interfaces; +using SecurityBusinessLogic.BusinessLogics; +using SecurityBusinessLogic.Interfaces; +using SecurityImplementation.Implementations; + +namespace SecurityImplementation +{ + public class SecurityLoaderExtensions : ILoaderExtensions + { + public void RegisterServices() + { + UnityContainerConfigurator.PublishService(); + UnityContainerConfigurator.PublishService(); + UnityContainerConfigurator.PublishService(); + UnityContainerConfigurator.PublishService(); + + UnityContainerConfigurator.PublishService(); + UnityContainerConfigurator.PublishService(); + UnityContainerConfigurator.PublishService(); + UnityContainerConfigurator.PublishService(); + } + } +} \ No newline at end of file