using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Keyapis.EF.DataAnnotations; using Keyapis.EF.Extensions; using Keyapis.EF.ValueConverters; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; // ReSharper disable once CheckNamespace namespace Keyapis.EF.EncryptionProfile.V1.Data.EncryptionProfileDb; public interface IEncryptionProfileDbContext : IAsyncDisposable, IDisposable { public DbSet EncryptionProfiles { get; set; } public Task SaveChangesAsync(CancellationToken cancellationToken = default); } public abstract class EncryptionProfileDbContextBase : DbContext, IEncryptionProfileDbContext { protected EncryptionProfileDbContextBase(DbContextOptions options) : base(options) { } public DbSet EncryptionProfiles { get; set; } = null!; protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.HasPostgresExtension("pg_trgm"); foreach(var entity in builder.Model.GetEntityTypes()) { foreach(var property in entity.GetProperties()) { var memberInfo = property.PropertyInfo ?? (MemberInfo ?)property.FieldInfo; if (memberInfo == null) continue; var customRangeAttribute = memberInfo.GetCustomAttribute(); if (customRangeAttribute != null) { var actualType = Nullable.GetUnderlyingType(property.ClrType) ?? property.ClrType; if (actualType == typeof(string) || typeof(IEnumerable).IsAssignableFrom(actualType)) { property.SetMaxLength(customRangeAttribute.Maximum > int.MaxValue ? int.MaxValue : (int)customRangeAttribute.Maximum); } } var customRequiredAttribute = memberInfo.GetCustomAttribute(); if (customRequiredAttribute != null) { property.IsNullable = false; } } } builder.Entity(e => { // Для поля id дополнительные конфигурации свойства не нужны // Найдено сопоставление: model.id ~ order.ID e.HasIndex(p => p.Id) .HasMethod("btree") .IsDescending(); // Для поля name дополнительные конфигурации свойства не нужны // Для поля name сопоствалений с фильтром и сортировкой не найденно // Для поля description дополнительные конфигурации свойства не нужны // Для поля description сопоствалений с фильтром и сортировкой не найденно e.Property(p => p.Type) .HasMaxLength(32) .HasConversion(new EnumToStringConverter()); // Найдено сопоставление: model.type ~ filter.types e.HasIndex(p => p.Type) .IsDescending(); // Для поля sector_number дополнительные конфигурации свойства не нужны // Для поля sector_number сопоствалений с фильтром и сортировкой не найденно // Для поля block_number дополнительные конфигурации свойства не нужны // Для поля block_number сопоствалений с фильтром и сортировкой не найденно // Для поля start_index дополнительные конфигурации свойства не нужны // Для поля start_index сопоствалений с фильтром и сортировкой не найденно // Для поля end_index дополнительные конфигурации свойства не нужны // Для поля end_index сопоствалений с фильтром и сортировкой не найденно // Для поля secret_a дополнительные конфигурации свойства не нужны // Для поля secret_a сопоствалений с фильтром и сортировкой не найденно // WARNING Для поля EncryptionProfile.encrypted_secret_a не указан диапазон // Для поля encrypted_secret_a дополнительные конфигурации свойства не нужны // Для поля encrypted_secret_a сопоствалений с фильтром и сортировкой не найденно // Для поля secret_b дополнительные конфигурации свойства не нужны // Для поля secret_b сопоствалений с фильтром и сортировкой не найденно // WARNING Для поля EncryptionProfile.encrypted_secret_b не указан диапазон // Для поля encrypted_secret_b дополнительные конфигурации свойства не нужны // Для поля encrypted_secret_b сопоствалений с фильтром и сортировкой не найденно e.Property(p => p.CreatedAt) .HasColumnType("timestamp without time zone") .HasConversion(DateTimeUtcConverter.Instance); // Найдено сопоставление: model.created_at ~ order.CREATED_AT e.HasIndex(p => p.CreatedAt) .HasMethod("btree") .IsDescending(); e.Property(p => p.ChangedAt) .HasColumnType("timestamp without time zone") .HasConversion(DateTimeUtcConverter.Instance) .IsConcurrencyToken(); // Найдено сопоставление: model.changed_at ~ order.CHANGED_AT e.HasIndex(p => p.ChangedAt) .HasMethod("btree") .IsDescending(); // WARNING Для поля EncryptionProfile.deleted_at не указан диапазон e.Property(p => p.DeletedAt) .HasColumnType("timestamp without time zone") .HasConversion(NullableDateTimeUtcConverter.Instance); // Для поля deleted_at сопоствалений с фильтром и сортировкой не найденно // Дополнительные индексы: // По полю EncryptionProfileFilter.(name,description) e.HasIndex(p => new { p.Name, p.Description }) .HasMethod("gin") .IsTsVectorExpressionIndex("russian"); }); builder.HasDefaultSchema("encryption_profile"); } } /// /// Профиль шифрования. /// # Описание модели /// [ Display(Name = @"Профиль шифрования"), Description(@"Описание модели") ] public partial class EncryptionProfileModel { /// /// Идентификатор. /// # Тип: Guid /// [ Display(Name = @"Идентификатор"), Description(@"Тип: Guid"), CustomPattern(@"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$") ] public Guid Id { get; set; } /// /// Наименование. /// # Диапазон: 3..64 /// [ Display(Name = @"Наименование"), Description(@"Диапазон: 3..64"), CustomRequired, CustomRange(3, 64) ] public string Name { get; set; } = null!; /// /// Описание. /// # Диапазон: 3..1000 /// [ Display(Name = @"Описание"), Description(@"Диапазон: 3..1000"), CustomRange(3, 1000) ] public string? Description { get; set; } /// /// Тип профиля шифрования /// [ Display(Name = @"Тип профиля шифрования"), CustomRequired ] public EncryptionProfileModel.EncryptionProfileType Type { get; set; } /// /// Номер сектора. /// # Диапазон: 0..15 /// [ Display(Name = @"Номер сектора"), Description(@"Диапазон: 0..15"), CustomRange(0, 15) ] public int SectorNumber { get; set; } /// /// Номер блока. /// # Диапазон: 0..3 /// [ Display(Name = @"Номер блока"), Description(@"Диапазон: 0..3"), CustomRange(0, 3) ] public int BlockNumber { get; set; } /// /// Индекс первого символа для секрета. /// # Диапазон: 0..31 /// [ Display(Name = @"Индекс первого символа для секрета"), Description(@"Диапазон: 0..31"), CustomRange(0, 31) ] public int StartIndex { get; set; } /// /// Индекс последнего символа для секрета. /// # Диапазон: 0..31 /// [ Display(Name = @"Индекс последнего символа для секрета"), Description(@"Диапазон: 0..31"), CustomRange(0, 31) ] public int EndIndex { get; set; } /// /// Пароль A профиля. /// # Диапазон: 16..32 /// [ Display(Name = @"Пароль A профиля"), Description(@"Диапазон: 16..32"), CustomRequired, CustomRange(16, 32) ] public string SecretA { get; set; } = null!; /// /// Зашифрованный пароль B профиля /// [ Display(Name = @"Зашифрованный пароль B профиля"), CustomRequired, Editable(false) ] public string EncryptedSecretA { get; set; } = null!; /// /// Пароль B профиля. /// # Диапазон: 16..32 /// [ Display(Name = @"Пароль B профиля"), Description(@"Диапазон: 16..32"), CustomRequired, CustomRange(16, 32) ] public string SecretB { get; set; } = null!; /// /// Зашифрованный пароль B профиля /// [ Display(Name = @"Зашифрованный пароль B профиля"), CustomRequired, Editable(false) ] public string EncryptedSecretB { get; set; } = null!; /// /// Дата создания. /// # Тип: DateTime /// [ Display(Name = @"Дата создания"), Description(@"Тип: DateTime"), Editable(false) ] public DateTime CreatedAt { get; set; } /// /// Дата последнего изменения. /// Заполняется и обновляется сервером. /// Заполняется при создании и изменении. /// Является версией объекта. /// # Тип: DateTime /// [ Display(Name = @"Дата последнего изменения"), Description(@"Заполняется и обновляется сервером. Заполняется при создании и изменении. Является версией объекта. Тип: DateTime") ] public DateTime ChangedAt { get; set; } /// /// Дата удаления. /// # Тип: DateTime? /// [ Display(Name = @"Дата удаления"), Description(@"Тип: DateTime?"), Editable(false) ] public DateTime? DeletedAt { get; set; } /// /// Ошибка сохранения. /// Эти проверки выполняются при работе с базой данных и сторонними сервисами /// [ Display(Name = @"Ошибка сохранения"), Description(@"Эти проверки выполняются при работе с базой данных и сторонними сервисами") ] public partial class SavingErrorModel { /// /// Конфликт версий /// [ Display(Name = @"Конфликт версий") ] public EncryptionProfileModel.SavingErrorModel.ConflictModel? Conflict { get; set; } /// /// Указанный диапазон не соответствует минимальному значению /// [ Display(Name = @"Указанный диапазон не соответствует минимальному значению") ] public EncryptionProfileModel.SavingErrorModel.RangeIsTooSmallModel? RangeIsTooSmall { get; set; } /// /// Конфликт версий. /// Причины: /// - В базе хранится другая версия строки, значения changed_at оличаются /// [ Display(Name = @"Конфликт версий"), Description(@"Причины: - В базе хранится другая версия строки, значения changed_at оличаются") ] public partial class ConflictModel { } /// /// Указанный диапазон не соответствует минимальному значению. /// Причины: /// - Модуль разности между полями start_index и end_index меньше 7 /// [ Display(Name = @"Указанный диапазон не соответствует минимальному значению"), Description(@"Причины: - Модуль разности между полями start_index и end_index меньше 7") ] public partial class RangeIsTooSmallModel { } } /// /// Справочник типов профиля шифрования. /// # Тип: byte /// [ Description("Тип: byte") ] public enum EncryptionProfileType : byte { /// /// Значение не указано /// [ Display(Name = @"Значение не указано"), JsonPropertyName("TYPE_UNKNOWN") ] Unknown = 0, /// /// Тип SL3 /// [ Display(Name = @"Тип SL3"), JsonPropertyName("SL3") ] Sl3 = 1, } } /// /// Фильтр по профилям шифрования /// [ Display(Name = @"Фильтр по профилям шифрования") ] public partial class EncryptionProfileFilterModel { /// /// Поиск по тексту. /// Если значение не передано то поиск по нему не производится. /// # Диапазон: 3..64. /// # Поиск производится по полям: /// # - Наименование; /// # - Описание /// [ Display(Name = @"Поиск по тексту"), Description(@"Если значение не передано то поиск по нему не производится. Диапазон: 3..64. Поиск производится по полям: - Наименование; - Описание"), CustomRange(3, 64) ] public string? Text { get; set; } /// /// По типам профиля шифрования /// [ Display(Name = @"По типам профиля шифрования") ] public List Types { get; set; } = new(0); /// /// Показывать удаленные /// [ Display(Name = @"Показывать удаленные") ] public bool? ShowDeleted { get; set; } } /// /// Запрос удаления профиля шифрования /// [ Display(Name = @"Запрос удаления профиля шифрования") ] public partial class DeleteEncryptionProfileRequestModel { /// /// Идентификатор. /// # Тип: Guid /// [ Display(Name = @"Идентификатор"), Description(@"Тип: Guid"), CustomRequired, CustomPattern(@"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$") ] public Guid Id { get; set; } } /// /// Ответ на запрос удаления профиля шифрования /// [ Display(Name = @"Ответ на запрос удаления профиля шифрования") ] public partial class DeleteEncryptionProfileResponseModel { /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public DeleteEncryptionProfileResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса удаления профиля шифрования /// [ Display(Name = @"Ошибка запроса удаления профиля шифрования") ] public partial class ErrorModel { /// /// Существуют устройства, связанные с этим профилем шифрования /// [ Display(Name = @"Существуют устройства, связанные с этим профилем шифрования") ] public DeleteEncryptionProfileResponseModel.ErrorModel.LinkedDevicesExistsModel? LinkedDevicesExists { get; set; } /// /// Существуют устройства, связанные с этим профилем шифрования. /// Следует отвязать устройства перед удалением профиля /// [ Display(Name = @"Существуют устройства, связанные с этим профилем шифрования"), Description(@"Следует отвязать устройства перед удалением профиля") ] public partial class LinkedDevicesExistsModel { } } } /// /// Постраничный вывод /// [ Display(Name = @"Постраничный вывод") ] public partial class EncryptionProfilePagingModel { /// /// Тип значения сортировки. /// Если значение не передано, то будет взято значение по умолчанию. /// # По умолчанию: CHANGED_AT /// [ Display(Name = @"Тип значения сортировки"), Description(@"Если значение не передано, то будет взято значение по умолчанию. По умолчанию: CHANGED_AT") ] public EncryptionProfilePagingModel.EncryptionProfilePagingOrderByType OrderByType { get; set; } = EncryptionProfilePagingOrderByType.ChangedAt; /// /// Тип направления сортировки. /// # По умолчанию: DESC /// [ Display(Name = @"Тип направления сортировки"), Description(@"По умолчанию: DESC") ] public EncryptionProfilePagingModel.EncryptionProfilePagingDirectionType DirectionType { get; set; } = EncryptionProfilePagingDirectionType.Desc; /// /// Количество записей на страницу. /// Если значение 0 (не передано), то будет взято значение по умолчанию. /// # Диапазон: 0..100. /// # По умолчанию: 20 /// [ Display(Name = @"Количество записей на страницу"), Description(@"Если значение 0 (не передано), то будет взято значение по умолчанию. Диапазон: 0..100. По умолчанию: 20"), CustomRange(0, 100) ] public int Limit { get; set; } = 20; /// /// Сдвиг. /// # Диапазон: 0..2147483647 /// [ Display(Name = @"Сдвиг"), Description(@"Диапазон: 0..2147483647"), CustomRange(0, 2147483647) ] public int Offset { get; set; } /// /// Справочник типов значений сортировки. /// # Тип: byte /// [ Description("Тип: byte") ] public enum EncryptionProfilePagingOrderByType : byte { /// /// Значение не указано /// [ Display(Name = @"Значение не указано"), JsonPropertyName("ORDER_BY_TYPE_UNKNOWN") ] Unknown = 0, /// /// По идентификатору /// [ Display(Name = @"По идентификатору"), JsonPropertyName("ID") ] Id = 1, /// /// Дата последнего изменения /// [ Display(Name = @"Дата последнего изменения"), JsonPropertyName("CHANGED_AT") ] ChangedAt = 2, /// /// Дата создания /// [ Display(Name = @"Дата создания"), JsonPropertyName("CREATED_AT") ] CreatedAt = 3, /// /// По рангу для поиска по тексту. /// Применяется когда передано поле для поиска по тексту. /// В случае если текстовое поле не передано, применяется значение по умолчанию /// [ Display(Name = @"По рангу для поиска по тексту"), Description(@"Применяется когда передано поле для поиска по тексту. В случае если текстовое поле не передано, применяется значение по умолчанию"), JsonPropertyName("RANK") ] Rank = 4, } /// /// Справочник типов направлений сортировки; /// # Тип: byte /// [ Description("Тип: byte") ] public enum EncryptionProfilePagingDirectionType : byte { /// /// Значение не указано /// [ Display(Name = @"Значение не указано"), JsonPropertyName("DIRECTION_TYPE_UNKNOWN") ] Unknown = 0, /// /// От большего к меньшему /// [ Display(Name = @"От большего к меньшему"), JsonPropertyName("DESC") ] Desc = 1, /// /// От меньшего к большему /// [ Display(Name = @"От меньшего к большему"), JsonPropertyName("ASC") ] Asc = 2, } } /// /// Запрос получения количества профилей шифрования /// [ Display(Name = @"Запрос получения количества профилей шифрования") ] public partial class GetEncryptionProfileCountRequestModel { /// /// Фильтр /// [ Display(Name = @"Фильтр") ] public EncryptionProfileFilterModel? Filter { get; set; } } /// /// Ответ на запрос получения количества профилей шифрования /// [ Display(Name = @"Ответ на запрос получения количества профилей шифрования") ] public partial class GetEncryptionProfileCountResponseModel { /// /// Всего устройтсв /// [ Display(Name = @"Всего устройтсв") ] public int Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public GetEncryptionProfileCountResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса получения количества профилей шифрования /// [ Display(Name = @"Ошибка запроса получения количества профилей шифрования") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос на получение списка профилей шифрования /// [ Display(Name = @"Запрос на получение списка профилей шифрования") ] public partial class GetEncryptionProfileListRequestModel { /// /// Фильтр /// [ Display(Name = @"Фильтр") ] public EncryptionProfileFilterModel? Filter { get; set; } /// /// Стандартный постраничный вывод /// [ Display(Name = @"Стандартный постраничный вывод") ] public EncryptionProfilePagingModel? Paging { get; set; } } /// /// Ответ на получение списка профилей шифрования /// [ Display(Name = @"Ответ на получение списка профилей шифрования") ] public partial class GetEncryptionProfileListResponseModel { /// /// Профиль шифрования /// [ Display(Name = @"Профиль шифрования") ] public EncryptionProfileModel? Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public GetEncryptionProfileListResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса получения списка профилей шифрования /// [ Display(Name = @"Ошибка запроса получения списка профилей шифрования") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос получения профиля шифрования /// [ Display(Name = @"Запрос получения профиля шифрования") ] public partial class GetEncryptionProfileRequestModel { /// /// Идентификатор. /// # Тип: Guid /// [ Display(Name = @"Идентификатор"), Description(@"Тип: Guid"), CustomRequired, CustomPattern(@"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$") ] public Guid Id { get; set; } } /// /// Ответ на запрос получения профиля шифрования /// [ Display(Name = @"Ответ на запрос получения профиля шифрования") ] public partial class GetEncryptionProfileResponseModel { /// /// Профиль шифрования /// [ Display(Name = @"Профиль шифрования") ] public EncryptionProfileModel? Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public GetEncryptionProfileResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса получения баннера /// [ Display(Name = @"Ошибка запроса получения баннера") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос сохранения шифрования по идентификатору /// [ Display(Name = @"Запрос сохранения шифрования по идентификатору") ] public partial class PostEncryptionProfileRequestModel { /// /// Профиль шифрования /// [ Display(Name = @"Профиль шифрования"), CustomRequired ] public EncryptionProfileModel Data { get; set; } = null!; } /// /// Ответ на запрос сохранения шифрования по идентификатору /// [ Display(Name = @"Ответ на запрос сохранения шифрования по идентификатору") ] public partial class PostEncryptionProfileResponseModel { /// /// Профиль шифрования /// [ Display(Name = @"Профиль шифрования") ] public EncryptionProfileModel? Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public PostEncryptionProfileResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса сохранения профиля шифрования /// [ Display(Name = @"Ошибка запроса сохранения профиля шифрования") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } /// /// Ошибка сохранения /// [ Display(Name = @"Ошибка сохранения") ] public EncryptionProfileModel.SavingErrorModel? Saving { get; set; } } } /// /// Запрос разархивации шифрования по идентификатору /// [ Display(Name = @"Запрос разархивации шифрования по идентификатору") ] public partial class PostEncryptionProfileRestoreRequestModel { /// /// Идентификатор. /// # Тип: Guid /// [ Display(Name = @"Идентификатор"), Description(@"Тип: Guid"), CustomRequired, CustomPattern(@"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$") ] public Guid Id { get; set; } } /// /// Отвест на запрос разархивации шифрования по идентификатору /// [ Display(Name = @"Отвест на запрос разархивации шифрования по идентификатору") ] public partial class PostEncryptionProfileRestoreResponseModel { } /// /// Ошибки валидации. /// Эти проверки выполняются до обращения в базу данных /// [ Display(Name = @"Ошибки валидации"), Description(@"Эти проверки выполняются до обращения в базу данных") ] public partial class ValidationErrorModel { /// /// Путь к полю в формате наименования прото /// [ Display(Name = @"Путь к полю в формате наименования прото"), CustomRequired ] public string Path { get; set; } = null!; /// /// Валидационное сообщение /// [ Display(Name = @"Валидационное сообщение"), CustomRequired ] public string Message { get; set; } = null!; } /// /// Запрос проверки доступности сервиса /// [ Display(Name = @"Запрос проверки доступности сервиса") ] public partial class GetSystemStatusRequestModel { } /// /// Ответ на запрос проверки доступности сервиса /// [ Display(Name = @"Ответ на запрос проверки доступности сервиса") ] public partial class GetSystemStatusResponseModel { }