using FluentValidation; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; using PARR.API.Contracts.V1.Requests; using PARR.DAL.Services.Interfaces; namespace PARR.API.Validators { public class ApplicationInWorkValidator : AbstractValidator { private readonly IApplicationsInWorkService applicationsInWorkService; private readonly IWorkService workService; private readonly IEsppSchTypeConfigService esppSchTypeConfigService; private readonly IWorkGroupService workGroupService; private readonly IEsppSchTypeValueService esppSchTypeValueService; public ApplicationInWorkValidator( IApplicationsInWorkService applicationsInWorkService, IWorkService workService, IEsppSchTypeConfigService esppSchTypeConfigService, IWorkGroupService workGroupService, IEsppSchTypeValueService esppSchTypeValueService ) { this.applicationsInWorkService = applicationsInWorkService; this.workService = workService; this.esppSchTypeConfigService = esppSchTypeConfigService; this.workGroupService = workGroupService; this.esppSchTypeValueService = esppSchTypeValueService; RuleFor(t => t.TemplateDuration) .NotNull().NotEmpty()//.WithMessage("Длительность данного задания на выполнение работ не может быть пустым") .Matches("^\\d{1,2}\\s\\d{1,2}[:]\\d{1,2}[:]\\d{1,2}$") //.WithMessage("Длительность данного задания на выполнение работ должна соответствовать шаблону dd hh:mm:ss(7 00:00:00)"); .WithMessage("Значение не соответствует шаблону dd hh:mm:ss(7 00:00:00)"); RuleFor(t => t.ShortDescription) .NotNull().NotEmpty();//.WithMessage("Краткое описание данного задания на выполнение работ не может быть пустым"); RuleFor(t => t.FullDescription) .NotNull().NotEmpty();//.WithMessage("Подробное описание данного задания на выполнение работ не может быть пустым"); RuleFor(t => t.Solution) .NotNull().NotEmpty();//.WithMessage("Решение данного задания на выполнение работ не может быть пустым"); RuleFor(t => t.WorkId) .MustAsync(async (entity, value, c) => await IsWorkExist(entity)) .WithMessage("Указан несуществующий Id работы"); //.WithMessage("У данного задания на выполнение работ указан несуществующий Id работы"); RuleFor(t => t.ApplicationId) .MustAsync(async (entity, value, c) => await IsApplicationExist(entity)) .WithMessage("Указан несуществующий Id программного обеспечения"); //.MustAsync(async (entity, value, c) => await AppInWorkIsUnique(entity)) // .WithMessage("Задание на выполнение работ с такими ПО и работой уже существует"); //.WithMessage("У данного задания на выполнение работ указан несуществующий Id программного обеспечения"); #region old schedule //Проверяем настройки планировщика //RuleFor(t => t.Schedule).NotNull().NotEmpty() // .WithMessage("Настройки планировщика задания на выполнение работ не могут быть пустыми"); //RuleFor(t => t.Schedule.EsppSchValues) // .NotNull().NotEmpty() // .When(t => t.Schedule != null) // .WithMessage("Настройки планировщика задания на выполнение работ не могут быть пустыми") // .Must((entity, value, c) => IsEsppSchValuesExist(entity)) // .WithMessage("Не удалось найти подходящую конфигруцию планировщика задания на выполнение работ"); #endregion //RuleFor(t => t.Schedule) // .NotNull().NotEmpty() // .When(t => t.Schedule.Count() > 0) // .WithMessage("Настройки планировщика не могут быть пустыми") // .Must((entity, value, c) => IsEsppSchValuesExist(entity.Schedule)) // .WithMessage("Не удалось найти подходящую конфигруцию планировщика задания"); #region comment //RuleFor(t => t.Schedule.Values) // .NotNull().NotEmpty().WithMessage($"Настройки значений планировщика задания на выполнение работ не могут быть пустыми") // .Must((entity, value, c) => IsScheduleTypeValueIdExist(entity)) // .When(t => t.Schedule != null).WithMessage("Не удалось найти подходящую конфигруцию планировщика задания на выполнение работ"); //RuleFor(t => t.Schedule.TypeScheduleId) // .NotNull().NotEmpty().WithMessage($"Тип планировщика задания на выполнение работ не может быть пустым") // .Must((entity, value, c) => IsTypeScheduleIdExist(entity)) // .When(t => t.Schedule != null).WithMessage($"Не удалось найти указанный тип планировщика задания на выполнение работ"); //RuleFor(t => t.Schedule.Values) // .NotNull().NotEmpty().WithMessage($"Настройки значений планировщика задания на выполнение работ не могут быть пустыми") // .Must((entity, value, c) => IsScheduleTypeValueIdExist(entity)) // .When(t => t.Schedule != null).WithMessage("Не удалось найти подходящую конфигруцию планировщика задания на выполнение работ"); #endregion RuleFor(t => t.WorkGroups) .MustAsync(async (entity, value, c) => await IsWorkGroupsExistAsync(entity)) .WithMessage("Указаные несуществующие Id рабочих групп"); //Автораспределение может быть включено, только если у EsppSchTypeValues не пустое поле DistributionPeriodId RuleFor(t => t.IsAutoDistributionEnabled) .MustAsync(async (entity, value, c) => await IsAllowAutoDistributionEnabledAsync(entity, value)) .WithMessage("Нельзя включить автораспределение для этого типа расписания"); } private async Task IsAllowAutoDistributionEnabledAsync(ApplicationInWorkRequest entity, bool value)//TODO JobGroupRequest { //Автораспределение может быть включено, только если у EsppSchTypeValues не пустое поле DistributionPeriodId if (value == false) return true; //Распределение включено, смотрим, разрешено ли оно в расписании //по идее, это расписание только с одним значением в EsppSchValues, но мы проверим у всех, но такого быть не может по хорошему //foreach (var item in entity.Schedule) //{ // var schVal = await esppSchTypeValueService.GetAsync(item.TypeValueId); // if (schVal != null) // if (schVal.DistributionPeriodId == null) // return false; //} return true; } private async Task IsWorkGroupsExistAsync(ApplicationInWorkRequest entity) { var result = await workGroupService.Get().Where(t => entity.WorkGroups.Contains(t.Id)).ToListAsync(); return entity.WorkGroups.Count() == result.Count(); } //private bool IsEsppSchValuesExist(ApplicationInWorkRequest request) private bool IsEsppSchValuesExist(List listSchedule) { var configs = esppSchTypeConfigService.GetWithSchIncludes().ToList(); //Проверяем полученные Id конфигураций и Id конфигураций в базе var typeConfigIdList = listSchedule.Select(t => t.TypeConfigId); var foundTypeConfigIdList = configs.Where(t => typeConfigIdList.Contains(t.Id)).Distinct(); if (foundTypeConfigIdList.Count() == 0 //Не найдено совпадений с базой || foundTypeConfigIdList.Select(t => t.TypeScheduleId).Distinct().Count() > 1) //или имеют разный тип планировщика return false; var typeScheduleId = foundTypeConfigIdList.Select(t => t.TypeScheduleId).FirstOrDefault(); if (foundTypeConfigIdList.Count() != configs.Where(t => t.TypeScheduleId == typeScheduleId).Count()) //не все typeConfig найдены в базе return false; //Теперь проверяем значения foreach (var item in listSchedule) { var curTypeConfig = configs.Where(t => t.Id == item.TypeConfigId).Single(); var isCurValueExist = curTypeConfig!.EsppSchType!.EsppSchTypeValues.Where(t => t.Id == item.TypeValueId).Any(); if (!isCurValueExist) return false; } return true; } //private async Task AppInWorkIsUnique(ApplicationInWorkRequest request) //{ // //уникальная запись по полям ApplicationId, WorkId // var existSameAiW = await applicationsInWorkService.GetAsync(request.ApplicationId, request.WorkId); // //TODO: тут спорно, нужна ли эта проверка? Мы же можем создать несколько РР на одно и тоже ПО но с разным расписанием? // //к тому же, в методе update, такой проверки нет! // //if (existSameAiW != null) // // return BadRequest(new Response(false, new List { // // new ErrorModel { Message = $"Уже существует задание на выполнение работ для программного обеспечения id({request.ApplicationId}) и работой id({request.WorkId})." } } // // )); // return existSameAiW == null; //} private async Task IsWorkExist(ApplicationInWorkRequest request) { return await workService.GetAsync(request.WorkId) != null; } private async Task IsApplicationExist(ApplicationInWorkRequest request) { return await workService.GetAsync(request.WorkId) != null; } //private bool IsTypeScheduleIdExist(ApplicationInWorkRequest request) //{ // var configs = esppSchTypeConfigService.GetWithSchIncludes().ToList(); //var result = configs.Where(t => t.TypeId == request.Schedule.TypeScheduleId).FirstOrDefault() != null; //return result; // return false; //} //private bool IsScheduleTypeValueIdExist(ApplicationInWorkRequest request) //{ // var configs = esppSchTypeConfigService.GetWithSchIncludes().ToList(); // var mustValues = configs.Where(t => t.TypeScheduleId == request.Schedule.TypeScheduleId).ToList(); // var values = request.Schedule.Values; // foreach (var mustValue in mustValues) // { // var mlValues = mustValue?.EsppSchType?.EsppSchTypeValues.Select(t => t.Id); // if (mlValues == null) // return false; // if (!mlValues.Intersect(values).Any()) // return false; // } // return true; //} } }