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

View File

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

View File

@ -1,18 +1,20 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {
#nullable enable
/// <inheritdoc/> /// <inheritdoc/>
public class UserTokenDto : UserExtendedDto public class UserTokenDto : UserExtendedDto
{ {
/// <summary> /// <summary>
/// все разрешения пользователя /// все разрешения пользователя
/// </summary> /// </summary>
public IEnumerable<PermissionDto> Permissions { get; set; } public IEnumerable<PermissionDto> Permissions { get; set; } = Enumerable.Empty<PermissionDto>();
/// <summary> /// <summary>
/// bearer token (для работы с web-api) /// bearer token (для работы с web-api)
/// </summary> /// </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")); NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Email") b.Property<string>("Email")
.IsRequired()
.HasMaxLength(255) .HasMaxLength(255)
.HasColumnType("character varying(255)") .HasColumnType("character varying(255)")
.HasColumnName("email") .HasColumnName("email")
.HasComment("должность"); .HasComment("должность");
b.Property<int?>("IdCompany") b.Property<int>("IdCompany")
.HasColumnType("integer") .HasColumnType("integer")
.HasColumnName("id_company"); .HasColumnName("id_company");
@ -3810,6 +3811,7 @@ namespace AsbCloudDb.Migrations
.HasComment("состояние:\n100 - удален"); .HasComment("состояние:\n100 - удален");
b.Property<string>("Login") b.Property<string>("Login")
.IsRequired()
.HasMaxLength(255) .HasMaxLength(255)
.HasColumnType("character varying(255)") .HasColumnType("character varying(255)")
.HasColumnName("login"); .HasColumnName("login");
@ -3821,6 +3823,7 @@ namespace AsbCloudDb.Migrations
.HasComment("имя"); .HasComment("имя");
b.Property<string>("PasswordHash") b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(255) .HasMaxLength(255)
.HasColumnType("character varying(255)") .HasColumnType("character varying(255)")
.HasColumnName("password_hash") .HasColumnName("password_hash")
@ -3865,6 +3868,7 @@ namespace AsbCloudDb.Migrations
new new
{ {
Id = 1, Id = 1,
Email = "",
IdCompany = 1, IdCompany = 1,
Login = "dev", Login = "dev",
Name = "Разработчик", Name = "Разработчик",
@ -3882,6 +3886,7 @@ namespace AsbCloudDb.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Caption") b.Property<string>("Caption")
.IsRequired()
.HasMaxLength(255) .HasMaxLength(255)
.HasColumnType("character varying(255)") .HasColumnType("character varying(255)")
.HasColumnName("caption") .HasColumnName("caption")
@ -6668,6 +6673,7 @@ namespace AsbCloudDb.Migrations
.WithMany("Users") .WithMany("Users")
.HasForeignKey("IdCompany") .HasForeignKey("IdCompany")
.OnDelete(DeleteBehavior.SetNull) .OnDelete(DeleteBehavior.SetNull)
.IsRequired()
.HasConstraintName("t_user_t_company_id_fk"); .HasConstraintName("t_user_t_company_id_fk");
b.Navigation("Company"); b.Navigation("Company");

View File

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

View File

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

View File

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

View File

@ -116,7 +116,7 @@ namespace AsbCloudInfrastructure.Repository
.GetAllAsync(token) .GetAllAsync(token)
.ConfigureAwait(false); .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) .OrderBy(x => x.Surname)
.Select(u => u as UserDto) .Select(u => u as UserDto)
.ToArray(); .ToArray();

View File

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

View File

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