Enable nullable on user, userRole

This commit is contained in:
ngfrolov 2023-02-20 12:18:45 +05:00
parent 1f8b7b7451
commit 942b2bca74
Signed by: ng.frolov
GPG Key ID: E99907A0357B29A7
16 changed files with 7259 additions and 81 deletions

View File

@ -1,5 +1,8 @@
namespace AsbCloudApp.Data
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data
{
#nullable enable
/// <summary>
/// DTO пользователя платформы
/// </summary>
@ -11,43 +14,47 @@
/// <summary>
/// логин
/// </summary>
public string Login { get; set; }
[Required]
[StringLength(255, MinimumLength = 2)]
public string Login { get; set; } = null!;
/// <summary>
/// Имя
/// </summary>
public string Name { get; set; }
public string? Name { get; set; }
/// <summary>
/// Фамилия
/// </summary>
public string Surname { get; set; }
public string? Surname { get; set; }
/// <summary>
/// Отчество
/// </summary>
public string Patronymic { get; set; }
public string? Patronymic { get; set; }
/// <summary>
/// Email
/// </summary>
public string Email { get; set; }
[Required]
[StringLength(255, MinimumLength = 6)]
public string Email { get; set; } = null!;
/// <summary>
/// Phone
/// </summary>
public string Phone { get; set; }
public string? Phone { get; set; }
/// <summary>
/// Должность
/// </summary>
public string Position { get; set; }
public string? Position { get; set; }
/// <summary>
/// Id компании
/// </summary>
public int? IdCompany { get; set; }
[Required]
public int IdCompany { get; set; }
/// <summary>
/// Id состояния пользователя
@ -57,7 +64,7 @@
/// <summary>
/// DTO компании
/// </summary>
public CompanyDto Company { get; set; }
public CompanyDto? Company { get; set; }
/// <summary>
/// Получение отображаемого имени

View File

@ -1,13 +1,15 @@
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudApp.Data
{
#nullable enable
/// <inheritdoc/>
public class UserExtendedDto : UserDto
{
/// <summary>
/// Роли пользователя
/// </summary>
public IEnumerable<string> RoleNames { get; set; }
public IEnumerable<string> RoleNames { get; set; } = Enumerable.Empty<string>();
}
}

View File

@ -1,11 +1,12 @@
namespace AsbCloudApp.Data
{
#nullable enable
/// <inheritdoc/>
public class UserRegistrationDto : UserDto
{
/// <summary>
/// пароль, используется только при регистрации.
/// </summary>
public string Password { get; set; }
public string Password { get; set; } = null!;
}
}

View File

@ -1,8 +1,10 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace AsbCloudApp.Data
{
#nullable enable
/// <summary>
/// Роль пользователя платформы
/// </summary>
@ -14,7 +16,8 @@ namespace AsbCloudApp.Data
/// <summary>
/// название
/// </summary>
public string Caption { get; set; }
[Required]
public string Caption { get; set; } = null!;
/// <summary>
/// id типа роли
@ -24,18 +27,11 @@ namespace AsbCloudApp.Data
/// <summary>
/// список разрешений
/// </summary>
public IEnumerable<PermissionDto> Permissions { get; set; }
public IEnumerable<PermissionDto> Permissions { get; set; } = Enumerable.Empty<PermissionDto>();
/// <summary>
/// Включенные роли
/// </summary>
public virtual IEnumerable<UserRoleDto> Roles { get; set; }
/// <summary>
/// Пользователи в роли
/// </summary>
[JsonIgnore]
public virtual ICollection<UserDto> Users { get; set; }
public virtual IEnumerable<UserRoleDto> Roles { get; set; } = Enumerable.Empty<UserRoleDto>();
}
}

View File

@ -1,18 +1,20 @@
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudApp.Data
{
#nullable enable
/// <inheritdoc/>
public class UserTokenDto : UserExtendedDto
{
/// <summary>
/// все разрешения пользователя
/// </summary>
public IEnumerable<PermissionDto> Permissions { get; set; }
public IEnumerable<PermissionDto> Permissions { get; set; } = Enumerable.Empty<PermissionDto>();
/// <summary>
/// bearer token (для работы с web-api)
/// </summary>
public string Token { get; set; }
public string Token { get; set; } = null!;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,143 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Enable_nullable_on_user_userRole : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("update t_user set email = '' where email is null;");
migrationBuilder.Sql("update t_user set password_hash = '' where password_hash is null;");
migrationBuilder.AlterColumn<string>(
name: "caption",
table: "t_user_role",
type: "character varying(255)",
maxLength: 255,
nullable: false,
defaultValue: "",
comment: "Название",
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true,
oldComment: "Название");
migrationBuilder.AlterColumn<string>(
name: "password_hash",
table: "t_user",
type: "character varying(255)",
maxLength: 255,
nullable: false,
defaultValue: "",
comment: "соленый хэш пароля.\nпервые 5 символов - соль",
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true,
oldComment: "соленый хэш пароля.\nпервые 5 символов - соль");
migrationBuilder.AlterColumn<string>(
name: "login",
table: "t_user",
type: "character varying(255)",
maxLength: 255,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<int>(
name: "id_company",
table: "t_user",
type: "integer",
nullable: false,
defaultValue: 0,
oldClrType: typeof(int),
oldType: "integer",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "email",
table: "t_user",
type: "character varying(255)",
maxLength: 255,
nullable: false,
defaultValue: "",
comment: "должность",
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true,
oldComment: "должность");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "caption",
table: "t_user_role",
type: "character varying(255)",
maxLength: 255,
nullable: true,
comment: "Название",
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldComment: "Название");
migrationBuilder.AlterColumn<string>(
name: "password_hash",
table: "t_user",
type: "character varying(255)",
maxLength: 255,
nullable: true,
comment: "соленый хэш пароля.\nпервые 5 символов - соль",
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldComment: "соленый хэш пароля.\nпервые 5 символов - соль");
migrationBuilder.AlterColumn<string>(
name: "login",
table: "t_user",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<int>(
name: "id_company",
table: "t_user",
type: "integer",
nullable: true,
oldClrType: typeof(int),
oldType: "integer");
migrationBuilder.AlterColumn<string>(
name: "email",
table: "t_user",
type: "character varying(255)",
maxLength: 255,
nullable: true,
comment: "должность",
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldComment: "должность");
migrationBuilder.UpdateData(
table: "t_user",
keyColumn: "id",
keyValue: 1,
column: "email",
value: null);
}
}
}

View File

@ -3795,12 +3795,13 @@ namespace AsbCloudDb.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("email")
.HasComment("должность");
b.Property<int?>("IdCompany")
b.Property<int>("IdCompany")
.HasColumnType("integer")
.HasColumnName("id_company");
@ -3810,6 +3811,7 @@ namespace AsbCloudDb.Migrations
.HasComment("состояние:\n100 - удален");
b.Property<string>("Login")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("login");
@ -3821,6 +3823,7 @@ namespace AsbCloudDb.Migrations
.HasComment("имя");
b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("password_hash")
@ -3865,6 +3868,7 @@ namespace AsbCloudDb.Migrations
new
{
Id = 1,
Email = "",
IdCompany = 1,
Login = "dev",
Name = "Разработчик",
@ -3882,6 +3886,7 @@ namespace AsbCloudDb.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Caption")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("caption")
@ -6668,6 +6673,7 @@ namespace AsbCloudDb.Migrations
.WithMany("Users")
.HasForeignKey("IdCompany")
.OnDelete(DeleteBehavior.SetNull)
.IsRequired()
.HasConstraintName("t_user_t_company_id_fk");
b.Navigation("Company");

View File

@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
#nullable disable
namespace AsbCloudDb.Model
{
[Table("t_user"), Comment("Пользователи облака")]
@ -15,56 +13,55 @@ namespace AsbCloudDb.Model
public int Id { get; set; }
[Column("id_company")]
public int? IdCompany { get; set; }
public int IdCompany { get; set; }
[Column("login")]
[StringLength(255)]
public string Login { get; set; }
public string Login { get; set; } = null!;
[Column("password_hash"), Comment("соленый хэш пароля.\nпервые 5 символов - соль")]
[StringLength(255)]
public string PasswordHash { get; set; }
public string PasswordHash { get; set; } = null!;
[Column("state"), Comment("состояние:\n100 - удален")]
public short? IdState { get; set; }
[Column("name"), Comment("имя")]
[StringLength(255)]
public string Name { get; set; }
public string? Name { get; set; }
[Column("surname"), Comment("фамилия")]
[StringLength(255)]
public string Surname { get; set; }
public string? Surname { get; set; }
[Column("patronymic"), Comment("отчество")]
[StringLength(255)]
public string Patronymic { get; set; }
public string? Patronymic { get; set; }
[Column("email"), Comment("должность")]
[StringLength(255)]
public string Email { get; set; }
public string Email { get; set; } = string.Empty;
[Column("phone"), Comment("номер телефона")]
[StringLength(50)]
public string Phone { get; set; }
public string? Phone { get; set; }
[Column("position"), Comment("email")]
[StringLength(255)]
public string Position { get; set; }
public string? Position { get; set; }
[ForeignKey(nameof(IdCompany))]
[InverseProperty(nameof(Model.Company.Users))]
public virtual Company Company { get; set; }
public virtual Company Company { get; set; } = null!;
[InverseProperty(nameof(RelationUserUserRole.User))]
public virtual ICollection<RelationUserUserRole> RelationUsersUserRoles { get; set; }
public virtual ICollection<RelationUserUserRole> RelationUsersUserRoles { get; set; } = null!;
[InverseProperty(nameof(FileInfo.Author))]
public virtual ICollection<FileInfo> Files { get; set; }
[InverseProperty(nameof(FileInfo.Author))]
public virtual ICollection<FileInfo> Files { get; set; } = null!;
[InverseProperty(nameof(FileMark.User))]
public virtual ICollection<FileMark> FileMarks { get; set; }
public virtual ICollection<FileMark> FileMarks { get; set; } = null!;
public string MakeDisplayName()
{

View File

@ -5,7 +5,6 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model
{
#nullable disable
[Table("t_user_role"), Comment("Роли пользователей в системе")]
public class UserRole : IId
{
@ -14,20 +13,20 @@ namespace AsbCloudDb.Model
public int Id { get; set; }
[Column("caption"), Comment("Название")]
[StringLength(255)]
public string Caption { get; set; }
[StringLength(255, MinimumLength = 2)]
public string Caption { get; set; } = null!;
[Column("id_type"), Comment("0-роль из стандартной матрицы, \n1-специальная роль для какого-либо пользователя")]
public int IdType { get; set; }
[InverseProperty(nameof(RelationUserRoleUserRole.Role))]
public virtual ICollection<RelationUserRoleUserRole> RelationUserRoleUserRoles { get; set; }
public virtual ICollection<RelationUserRoleUserRole> RelationUserRoleUserRoles { get; set; } = null!;
[InverseProperty(nameof(RelationUserUserRole.UserRole))]
public virtual ICollection<RelationUserUserRole> RelationUsersUserRoles { get; set; }
public virtual ICollection<RelationUserUserRole> RelationUsersUserRoles { get; set; } = null!;
[InverseProperty(nameof(RelationUserRolePermission.UserRole))]
public virtual ICollection<RelationUserRolePermission> RelationUserRolePermissions { get; set; }
public virtual ICollection<RelationUserRolePermission> RelationUserRolePermissions { get; set; } = null!;
}
}

View File

@ -6,7 +6,6 @@ using System.Text.Json;
namespace AsbCloudDb.Model
{
[Table("t_user_settings"), Comment("настройки интерфейса пользователя")]
public class UserSetting
{

View File

@ -271,7 +271,11 @@ namespace AsbCloudInfrastructure.Repository
{
var entity = dto.Adapt<User>(userTypeAdapterConfig);
if (string.IsNullOrEmpty(entity.PasswordHash))
entity.PasswordHash = dbContext.Users.FirstOrDefault(u => u.Id == dto.Id)?.PasswordHash;
{
var hash = dbContext.Users.FirstOrDefault(u => u.Id == dto.Id)?.PasswordHash;
entity.PasswordHash = hash ?? string.Empty;
}
return entity;
}
protected virtual UserExtendedDto Convert(User entity)

View File

@ -32,15 +32,19 @@ namespace AsbCloudInfrastructure.Repository
public async Task<int> InsertAsync(UserRoleDto dto, CancellationToken token)
{
var entity = dto.Adapt<UserRole>();
var updatedEntity = await dbContext.UserRoles.AddAsync(entity, token)
.ConfigureAwait(false);
dto.Id = updatedEntity.Entity.Id;
await UpdatePermissionsAsync(dto, token);
await UpdateIncludedRolesAsync(dto, token);
var updatedEntity = dbContext.UserRoles.Add(entity);
await dbContext.SaveChangesAsync(token);
DropCacheUserRole();
return updatedEntity.Entity.Id;
if (updatedEntity.IsKeySet)
{
dto.Id = updatedEntity.Entity.Id;
await UpdatePermissionsAsync(dto, token);
await UpdateIncludedRolesAsync(dto, token);
DropCacheUserRole();
return updatedEntity.Entity.Id;
}
return 0;
}
public Task<int> InsertRangeAsync(IEnumerable<UserRoleDto> newItems, CancellationToken token)
@ -54,7 +58,6 @@ namespace AsbCloudInfrastructure.Repository
.ConfigureAwait(false);
return entities.Select(Convert);
}
public UserRoleDto? GetOrDefault(int id)
@ -188,27 +191,25 @@ namespace AsbCloudInfrastructure.Repository
private async Task UpdateIncludedRolesAsync(UserRoleDto dto, CancellationToken token)
{
if (dto?.Roles is null)
if (!dto.Roles.Any())
return;
var idsIncludeRole = GetNestedByIds(dto.Roles.Select(x => x.Id)).Select(x => x.Id);
if (idsIncludeRole is not null && idsIncludeRole.Any(x => x == dto.Id))
if (idsIncludeRole.Any(x => x == dto.Id))
throw new ArgumentInvalidException("Invalid include role (self reference)", nameof(dto));
var relations = await dbContext.RelationUserRoleUserRoles
.Where(r => r.Id == dto.Id)
.ToListAsync(token)
.ConfigureAwait(false);
var removeRelationsQuery = dbContext.RelationUserRoleUserRoles
.Where(r => r.Id == dto.Id);
dbContext.RelationUserRoleUserRoles.RemoveRange(relations);
if (dto.Roles.Any())
{
var newRelations = dto.Roles.Select(r => new RelationUserRoleUserRole { Id = dto.Id, IdInclude = r.Id });
await dbContext.RelationUserRoleUserRoles.AddRangeAsync(newRelations, token);
await dbContext.SaveChangesAsync(token);
}
dbContext.RelationUserRoleUserRoles.RemoveRange(removeRelationsQuery);
var newRelations = dto.Roles.Select(r => new RelationUserRoleUserRole
{
Id = dto.Id,
IdInclude = r.Id,
});
dbContext.RelationUserRoleUserRoles.AddRange(newRelations);
await dbContext.SaveChangesAsync(token);
DropCacheRelationUserRoleUserRole();
}

View File

@ -116,7 +116,7 @@ namespace AsbCloudInfrastructure.Repository
.GetAllAsync(token)
.ConfigureAwait(false);
return allUsers.Where(x => x.IdCompany is not null && companyIds.Contains(x.IdCompany ?? int.MinValue))
return allUsers.Where(x => companyIds.Contains(x.IdCompany))
.OrderBy(x => x.Surname)
.Select(u => u as UserDto)
.ToArray();

View File

@ -84,7 +84,7 @@ namespace AsbCloudInfrastructure.Services
if (userDto.Password is null || userDto.Password.Length is < 3 or > 50)
return -2;
if (userDto.Email?.Length > 255)
if (userDto.Email.Length > 255)
return -3;
if (userDto.Phone?.Length > 50)
@ -126,7 +126,7 @@ namespace AsbCloudInfrastructure.Services
});
db.SaveChanges();
}
catch //(Exception ex)
catch
{
return -7;
}
@ -208,7 +208,7 @@ namespace AsbCloudInfrastructure.Services
{
new (claimIdUser, user.Id.ToString()),
new (ClaimsIdentity.DefaultNameClaimType, user.Login),
new (claimNameIdCompany, user.IdCompany?.ToString()!),
new (claimNameIdCompany, user.IdCompany.ToString()),
};
var roles = userRepository.GetRolesByIdUser(user.Id);
if (roles is not null)

View File

@ -72,7 +72,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
.SetValue(user.Position);
sheet.Cell(3, 5)
.SetValue(user.Company.Caption);
.SetValue(user.Company?.Caption);
sheet.Cell(4, 5)
.SetValue($"{user.Surname} {user.Name} {user.Patronymic}");
@ -141,7 +141,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
sheet.Range(startRow + 2, startCol + 1, startRow + 3, startCol + 1)
.Merge()
.SetValue(user.Company.Caption);
.SetValue(user.Company?.Caption);
sheet.Range(startRow + 4, startCol, startRow + 4, startCol + 1)
.Merge()