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.Notification.V1.Data.NotificationDb; public interface INotificationDbContext : IAsyncDisposable, IDisposable { public DbSet PushTokens { get; set; } public Task SaveChangesAsync(CancellationToken cancellationToken = default); } public abstract class NotificationDbContextBase : DbContext, INotificationDbContext { protected NotificationDbContextBase(DbContextOptions options) : base(options) { } public DbSet PushTokens { 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(); e.Property(p => p.Type) .HasMaxLength(32) .HasConversion(new EnumToStringConverter()); // Найдено сопоставление: model.type ~ filter.types e.HasIndex(p => p.Type) .IsDescending(); // Для поля token дополнительные конфигурации свойства не нужны // Для поля token сопоствалений с фильтром и сортировкой не найденно // Для поля user_app_id дополнительные конфигурации свойства не нужны // Найдено сопоставление: model.user_app_id ~ filter.user_app_ids e.HasIndex(p => p.UserAppId) .IsDescending(); // Для поля user_id дополнительные конфигурации свойства не нужны // Найдено сопоставление: model.user_id ~ filter.user_ids e.HasIndex(p => p.UserId) .IsDescending(); 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(); // Для поля app_version дополнительные конфигурации свойства не нужны // Для поля app_version сопоствалений с фильтром и сортировкой не найденно // WARNING Не удалось найти свойство навигации для поля PushToken.user_app_id // WARNING Не удалось найти свойство навигации для поля PushToken.user_id }); builder.HasDefaultSchema("notification"); } } /// /// Пуш-токен. /// # Описание модели /// [ Display(Name = @"Пуш-токен"), Description(@"Описание модели") ] public partial class PushTokenModel { /// /// Идентификатор. /// # Диапазон: 0..2147483647 /// [ Display(Name = @"Идентификатор"), Description(@"Диапазон: 0..2147483647"), CustomRange(0, 2147483647) ] public int Id { get; set; } /// /// Тип /// [ Display(Name = @"Тип"), CustomRequired ] public PushTokenModel.PushTokenType Type { get; set; } /// /// Токен. /// # Диапазон: 16..256 /// [ Display(Name = @"Токен"), Description(@"Диапазон: 16..256"), CustomRequired, CustomRange(16, 256) ] public string Token { get; set; } = null!; /// /// Идентификатор устройства пользователя. /// # Тип: 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 UserAppId { get; set; } // WARNING Не удалось найти свойство навигации для поля PushToken.user_app_id /// /// Идентификатор пользователя. /// # Диапазон: 1..2147483647 /// [ Display(Name = @"Идентификатор пользователя"), Description(@"Диапазон: 1..2147483647"), CustomRange(1, 2147483647), Editable(false) ] public int? UserId { get; set; } // WARNING Не удалось найти свойство навигации для поля PushToken.user_id /// /// Дата и время создания. /// # Тип: DateTime /// [ Display(Name = @"Дата и время создания"), Description(@"Тип: DateTime"), Editable(false) ] public DateTime CreatedAt { get; set; } /// /// Дата последнего изменения. /// Заполняется и обновляется сервером. /// Заполняется при создании и изменении. /// Является версией объекта. /// # Тип: DateTime /// [ Display(Name = @"Дата последнего изменения"), Description(@"Заполняется и обновляется сервером. Заполняется при создании и изменении. Является версией объекта. Тип: DateTime"), Editable(false) ] public DateTime ChangedAt { get; set; } /// /// Версия приложения. /// # Диапазон: 3..256 /// [ Display(Name = @"Версия приложения"), Description(@"Диапазон: 3..256"), CustomRequired, CustomRange(3, 256) ] public string AppVersion { get; set; } = null!; /// /// Ошибка сохранения пуш-токена. /// Эти проверки выполняются при работе с базой данных и сторонними сервисами /// [ Display(Name = @"Ошибка сохранения пуш-токена"), Description(@"Эти проверки выполняются при работе с базой данных и сторонними сервисами") ] public partial class SavingErrorModel { /// /// Идентификатор устройства пользователя уже используется /// [ Display(Name = @"Идентификатор устройства пользователя уже используется") ] public PushTokenModel.SavingErrorModel.UserAppIdExistsModel? UserAppIdExists { get; set; } /// /// Конфликт версий /// [ Display(Name = @"Конфликт версий") ] public PushTokenModel.SavingErrorModel.ConflictModel? Conflict { get; set; } /// /// Причины: /// - Переданный индентификатор устройства пользователя уже существует с другим токеном /// [ Display(Name = @"Причины:"), Description(@" - Переданный индентификатор устройства пользователя уже существует с другим токеном") ] public partial class UserAppIdExistsModel { } /// /// Конфликт версий. /// Причины: /// - В базе хранится другая версия строки, значения changed_at отличаются /// [ Display(Name = @"Конфликт версий"), Description(@"Причины: - В базе хранится другая версия строки, значения changed_at отличаются") ] public partial class ConflictModel { } } /// /// Ошибка валидации пуш-токена. /// Эти проверки выполняются до обращения в базу данных /// [ Display(Name = @"Ошибка валидации пуш-токена"), Description(@"Эти проверки выполняются до обращения в базу данных") ] public partial class ValidationErrorModel { /// /// Передан некоректный идентификатор устройства пользователя /// [ Display(Name = @"Передан некоректный идентификатор устройства пользователя") ] public PushTokenModel.ValidationErrorModel.UserAppIdInvalidModel? UserAppId { get; set; } // WARNING Не удалось найти свойство навигации для поля PushToken.ValidationError.user_app_id /// /// Причины: /// - Cодержит значение не Guid /// [ Display(Name = @"Причины:"), Description(@"- Cодержит значение не Guid") ] public partial class UserAppIdInvalidModel { } } /// /// Справочников типов пуш-токенов. /// # Тип: byte /// [ Description("Тип: byte") ] public enum PushTokenType : byte { /// /// Не указан /// [ Display(Name = @"Не указан"), JsonPropertyName("TYPE_UNKNOWN") ] Unknown = 0, /// /// Для Mobile Firebase Cloud Messaging /// [ Display(Name = @"Для Mobile Firebase Cloud Messaging"), JsonPropertyName("MOBILE_FCM") ] MobileFcm = 1, /// /// Для Mobile Huawei Messaging System /// [ Display(Name = @"Для Mobile Huawei Messaging System"), JsonPropertyName("MOBILE_HMS") ] MobileHms = 2, /// /// Для Mobile Apple PushToken System для текста /// [ Display(Name = @"Для Mobile Apple PushToken System для текста"), JsonPropertyName("MOBILE_APNS_TEXT") ] MobileApnsText = 3, /// /// Для Mobile Apple PushToken System для звонков /// [ Display(Name = @"Для Mobile Apple PushToken System для звонков"), JsonPropertyName("MOBILE_APNS_CALL") ] MobileApnsCall = 4, /// /// Для PWA Firebase Cloud Messaging /// [ Display(Name = @"Для PWA Firebase Cloud Messaging"), JsonPropertyName("PWA_FCM") ] PwaFcm = 5, /// /// Для PWA Apple PushToken System /// [ Display(Name = @"Для PWA Apple PushToken System"), JsonPropertyName("PWA_APNS") ] PwaApns = 6, /// /// Для Mobile RuStore /// [ Display(Name = @"Для Mobile RuStore"), JsonPropertyName("MOBILE_RUSTORE") ] MobileRustore = 7, } } /// /// Фильтр по пуш-токенам /// [ Display(Name = @"Фильтр по пуш-токенам") ] public partial class PushTokenFilterModel { /// /// По типам пуш-токенов /// [ Display(Name = @"По типам пуш-токенов") ] public List Types { get; set; } = new(0); /// /// По идентификаторам устройств пользователя. /// # Тип: 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 List UserAppIds { get; set; } = new(0); /// /// По идентификаторам пользователя /// [ Display(Name = @"По идентификаторам пользователя") ] public List UserIds { get; set; } = new(0); /// /// От даты создания включительно (>=) /// [ Display(Name = @"От даты создания включительно") ] public DateTime? BeginCreatedAt { get; set; } /// /// До даты создания (<) /// [ Display(Name = @"До даты создания") ] public DateTime? EndCreatedAt { get; set; } /// /// От даты изменения включительно (>=) /// [ Display(Name = @"От даты изменения включительно") ] public DateTime? BeginChangedAt { get; set; } /// /// До даты изменения (<) /// [ Display(Name = @"До даты изменения") ] public DateTime? EndChangedAt { get; set; } /// /// Ошибки валидации фильтра по фильтру пуш-токенов. /// Эти проверки выполняются до обращения в базу данных /// [ Display(Name = @"Ошибки валидации фильтра по фильтру пуш-токенов"), Description(@"Эти проверки выполняются до обращения в базу данных") ] public partial class ValidationErrorModel { /// /// Идентификаторы устройств пользователя переданы некоректно /// [ Display(Name = @"Идентификаторы устройств пользователя переданы некоректно") ] public PushTokenFilterModel.ValidationErrorModel.UserAppIdsInvalidModel? UserAppIds { get; set; } /// /// Причины: /// - Cодержит значение не Guid /// [ Display(Name = @"Причины:"), Description(@"- Cодержит значение не Guid") ] public partial class UserAppIdsInvalidModel { } } } /// /// Запрос удаления пуш-токена /// [ Display(Name = @"Запрос удаления пуш-токена") ] public partial class DeletePushTokenRequestModel { /// /// Идентификатор. /// # Диапазон: 0..2147483647 /// [ Display(Name = @"Идентификатор"), Description(@"Диапазон: 0..2147483647"), CustomRequired, CustomRange(0, 2147483647) ] public int Id { get; set; } } /// /// Ответ на запрос удаления пуш-токена /// [ Display(Name = @"Ответ на запрос удаления пуш-токена") ] public partial class DeletePushTokenResponseModel { /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public DeletePushTokenResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка удаления пуш-токена /// [ Display(Name = @"Ошибка удаления пуш-токена") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос удаления пуш-токена по идентификатору устройства пользователя /// [ Display(Name = @"Запрос удаления пуш-токена по идентификатору устройства пользователя") ] public partial class DeletePushTokenUserAppIdRequestModel { /// /// Идентификатор устройства пользователя. /// # Тип: 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 UserAppId { get; set; } // WARNING Не удалось найти свойство навигации для поля DeletePushTokenUserAppIdRequest.user_app_id } /// /// Ответ на запрос удаления пуш-токена по идентификатору устройства пользователя /// [ Display(Name = @"Ответ на запрос удаления пуш-токена по идентификатору устройства пользователя") ] public partial class DeletePushTokenUserAppIdResponseModel { /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public DeletePushTokenUserAppIdResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка удаления пуш-токена /// [ Display(Name = @"Ошибка удаления пуш-токена") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос удаления пуш-токенов по идентификатору пользователя /// [ Display(Name = @"Запрос удаления пуш-токенов по идентификатору пользователя") ] public partial class DeletePushTokenUserIdRequestModel { /// /// Идентификатор пользователя. /// # Диапазон: 1..2147483647 /// [ Display(Name = @"Идентификатор пользователя"), Description(@"Диапазон: 1..2147483647"), CustomRequired, CustomRange(1, 2147483647) ] public int UserId { get; set; } // WARNING Не удалось найти свойство навигации для поля DeletePushTokenUserIdRequest.user_id } /// /// Ответ на запрос удаления пуш-токенов по идентификатору пользователя /// [ Display(Name = @"Ответ на запрос удаления пуш-токенов по идентификатору пользователя") ] public partial class DeletePushTokenUserIdResponseModel { /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public DeletePushTokenUserIdResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка удаления пуш-токенов /// [ Display(Name = @"Ошибка удаления пуш-токенов") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос получения количества пуш-токенов /// [ Display(Name = @"Запрос получения количества пуш-токенов") ] public partial class GetPushTokenCountRequestModel { /// /// Фильтр /// [ Display(Name = @"Фильтр") ] public PushTokenFilterModel? Filter { get; set; } } /// /// Ответ на запрос получения количества пуш-токенов /// [ Display(Name = @"Ответ на запрос получения количества пуш-токенов") ] public partial class GetPushTokenCountResponseModel { /// /// Всего пуш-токенов /// [ Display(Name = @"Всего пуш-токенов") ] public int Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public GetPushTokenCountResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса получения количества пуш-токенов /// [ Display(Name = @"Ошибка запроса получения количества пуш-токенов") ] public partial class ErrorModel { /// /// Ошибка фильтрации /// [ Obsolete("Поле использовать нельзя. Добавлено для совместимости со старыми флоу."), Display(Name = @"Ошибка фильтрации") ] public PushTokenFilterModel.ValidationErrorModel? PushTokenFilterValidation { get; set; } /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос на получение пуш-токенов пользователя /// [ Display(Name = @"Запрос на получение пуш-токенов пользователя") ] public partial class GetPushTokenListRequestModel { /// /// Фильтр /// [ Display(Name = @"Фильтр") ] public PushTokenFilterModel? Filter { get; set; } /// /// Стандартный постраничный вывод /// [ Display(Name = @"Стандартный постраничный вывод") ] public PushTokenPagingModel? Paging { get; set; } } /// /// Ответ на получение списка пуш-токенов /// [ Display(Name = @"Ответ на получение списка пуш-токенов") ] public partial class GetPushTokenListResponseModel { /// /// Пуш-токен /// [ Display(Name = @"Пуш-токен") ] public PushTokenModel? Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public GetPushTokenListResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса получения списка пуш-токенов /// [ Display(Name = @"Ошибка запроса получения списка пуш-токенов") ] public partial class ErrorModel { /// /// Ошибка фильтрации /// [ Obsolete("Поле использовать нельзя. Добавлено для совместимости со старыми флоу."), Display(Name = @"Ошибка фильтрации") ] public PushTokenFilterModel.ValidationErrorModel? PushTokenFilterValidation { get; set; } /// /// Ошибка пагинации по страницам /// [ Obsolete("Поле использовать нельзя. Добавлено для совместимости со старыми флоу."), Display(Name = @"Ошибка пагинации по страницам") ] public PushTokenPagingModel.ValidationErrorModel? PushTokenPagingValidation { get; set; } /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос на создание/изменение пуш-токена /// [ Display(Name = @"Запрос на создание/изменение пуш-токена") ] public partial class PostPushTokenRequestModel { /// /// Пуш-токен /// [ Display(Name = @"Пуш-токен"), CustomRequired ] public PushTokenModel Data { get; set; } = null!; } /// /// Ответ на запрос на создание/изменение пуш-токена /// [ Display(Name = @"Ответ на запрос на создание/изменение пуш-токена") ] public partial class PostPushTokenResponseModel { /// /// Пуш-токен /// [ Display(Name = @"Пуш-токен") ] public PushTokenModel? Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public PostPushTokenResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса сохранения пуш-токена /// [ Display(Name = @"Ошибка запроса сохранения пуш-токена") ] public partial class ErrorModel { /// /// Ошибка валидации пуш-токена /// [ Obsolete("Поле использовать нельзя. Добавлено для совместимости со старыми флоу."), Display(Name = @"Ошибка валидации пуш-токена") ] public PushTokenModel.ValidationErrorModel? PushTokenValidation { get; set; } /// /// Ошибка сохранения пуш-токена /// [ Display(Name = @"Ошибка сохранения пуш-токена") ] public PushTokenModel.SavingErrorModel? PushTokenSaving { get; set; } /// /// Ошибка валидации пуш-токена /// [ Display(Name = @"Ошибка валидации пуш-токена") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Постраничный вывод /// [ Display(Name = @"Постраничный вывод") ] public partial class PushTokenPagingModel { /// /// Тип значения сортировки. /// Если значение не передано, то будет взято значение по умолчанию. /// # По умолчанию: ID /// [ Display(Name = @"Тип значения сортировки"), Description(@"Если значение не передано, то будет взято значение по умолчанию. По умолчанию: ID") ] public PushTokenPagingModel.PushTokenPagingOrderByType OrderByType { get; set; } = PushTokenPagingOrderByType.Id; /// /// Тип направления сортировки. /// # По умолчанию: DESC /// [ Display(Name = @"Тип направления сортировки"), Description(@"По умолчанию: DESC") ] public PushTokenPagingModel.PushTokenPagingDirectionType DirectionType { get; set; } = PushTokenPagingDirectionType.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; } /// /// Ошибка валидации постраничной пагинации по пуш-токенам. /// Эти проверки выполняются до обращения в базу данных /// [ Display(Name = @"Ошибка валидации постраничной пагинации по пуш-токенам"), Description(@"Эти проверки выполняются до обращения в базу данных") ] public partial class ValidationErrorModel { /// /// Количество передано некорректно /// [ Display(Name = @"Количество передано некорректно") ] public PushTokenPagingModel.ValidationErrorModel.LimitInvalidModel? Limit { get; set; } /// /// Сдвиг передан некорректно /// [ Display(Name = @"Сдвиг передан некорректно") ] public PushTokenPagingModel.ValidationErrorModel.OffsetInvalidModel? Offset { get; set; } /// /// Причины: /// - Значение количества < 0 или > 100 /// [ Display(Name = @"Причины:"), Description(@"- Значение количества < 0 или > 100") ] public partial class LimitInvalidModel { } /// /// Причины: /// - Значение сдвига < 0 /// [ Display(Name = @"Причины:"), Description(@"- Значение сдвига < 0") ] public partial class OffsetInvalidModel { } } /// /// Справочник типов значений сортировки. /// # Тип: byte /// [ Description("Тип: byte") ] public enum PushTokenPagingOrderByType : byte { /// /// Значение не указано /// [ Display(Name = @"Значение не указано"), JsonPropertyName("ORDER_BY_TYPE_UNKNOWN") ] Unknown = 0, /// /// По идентификатору /// [ Display(Name = @"По идентификатору"), JsonPropertyName("ID") ] Id = 1, /// /// По времени создания /// [ Display(Name = @"По времени создания"), JsonPropertyName("CREATED_AT") ] CreatedAt = 2, /// /// По времени изменения /// [ Display(Name = @"По времени изменения"), JsonPropertyName("CHANGED_AT") ] ChangedAt = 3, } /// /// Справочник типов направлений сортировки. /// # Тип: byte /// [ Description("Тип: byte") ] public enum PushTokenPagingDirectionType : byte { /// /// Значение не указано /// [ Display(Name = @"Значение не указано"), JsonPropertyName("DIRECTION_TYPE_UNKNOWN") ] Unknown = 0, /// /// От большего к меньшему /// [ Display(Name = @"От большего к меньшему"), JsonPropertyName("DESC") ] Desc = 1, /// /// От меньшего к большему /// [ Display(Name = @"От меньшего к большему"), JsonPropertyName("ASC") ] Asc = 2, } } /// /// Ошибки валидации. /// Эти проверки выполняются до обращения в базу данных /// [ 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 { }