From a642e76e80588fb1af4bdf4359f50da3b05850eb Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Wed, 10 Apr 2024 11:54:54 +1000 Subject: [PATCH] =?UTF-8?q?feat(api):=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=20AppInWorkController.=20=D0=A3=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=89=D0=B5=D0=BD=20request,=20=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D1=80.=20=D0=92=20update=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D1=81?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D1=8F.=20=D0=9C=D0=B5?= =?UTF-8?q?=D1=82=D0=BE=D0=B4=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D1=81=D1=80=D0=B0=D0=B1=D0=B0=D1=82=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D0=B5=D1=82=20=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=B5?= =?UTF-8?q?=D1=81=D0=BB=D0=B8=20=D0=BD=D0=B5=D1=82=20=D1=81=D0=B2=D1=8F?= =?UTF-8?q?=D0=B7=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D1=88=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=BE=D0=BD=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../V1/Requests/ApplicationInWorkRequest.cs | 14 +- .../V1/ApplicationInWorkController.cs | 206 ++++++++++-------- .../Validators/ApplicationInWorkValidator.cs | 51 +++-- 3 files changed, 165 insertions(+), 106 deletions(-) diff --git a/PARR.API/Contracts/V1/Requests/ApplicationInWorkRequest.cs b/PARR.API/Contracts/V1/Requests/ApplicationInWorkRequest.cs index afe8f167..d811c045 100644 --- a/PARR.API/Contracts/V1/Requests/ApplicationInWorkRequest.cs +++ b/PARR.API/Contracts/V1/Requests/ApplicationInWorkRequest.cs @@ -14,6 +14,7 @@ public required string FullDescription { get; set; } public required string Solution { get; set; } + public DateTimeOffset NextRun { get; set; } public bool IsAgent { get; set; } @@ -24,17 +25,18 @@ public string? AgentScript { get; set; } - public required ScheduleRequest Schedule { get; set; } + //public required ScheduleRequest Schedule { get; set; } + public List Schedule { get; set; } = new List(); } - public class ScheduleRequest - { - public DateTimeOffset NextRun { get; set; } + //public class ScheduleRequest + //{ + // public DateTimeOffset NextRun { get; set; } - public List EsppSchValues { get; set; } = new List(); - } + // public List EsppSchValues { get; set; } = new List(); + //} public class EsppSchValueRequest diff --git a/PARR.API/Controllers/V1/ApplicationInWorkController.cs b/PARR.API/Controllers/V1/ApplicationInWorkController.cs index 9b301f67..85a7e66a 100644 --- a/PARR.API/Controllers/V1/ApplicationInWorkController.cs +++ b/PARR.API/Controllers/V1/ApplicationInWorkController.cs @@ -18,9 +18,6 @@ using PARR.DAL.Services.Interfaces; namespace PARR.API.Controllers.V1 { - /// - /// ApplicationInWork - /// [Authorize(Roles = ParrRoles.Administrator.Role)] public class ApplicationInWorkController : BaseApiController { @@ -46,64 +43,6 @@ namespace PARR.API.Controllers.V1 } - /// - /// Создать задание на выполнение работ(ApplicationInWork) - /// - /// - /// - [HttpPost(ApiRoutes.Job.Create)] - public async Task Create([FromBody] ApplicationInWorkRequest request) - { - var resultValidate = await validator.ValidateAsync(request); - - if (!resultValidate.IsValid) - return BadRequest(new Response(resultValidate.Errors)); - - var existSameAiW = await applicationsInWorkService.GetAsync(request.ApplicationId, request.WorkId); - - if (existSameAiW != null) - return BadRequest(new Response(false, new List { - new ErrorModel { Message = $"Уже существует задание на выполнение работ для программного обеспечения id({request.ApplicationId}) и работой id({request.WorkId})." } } - )); - - var applicationInWork = new ApplicationsInWork - { - Id = Guid.NewGuid(), - WorkId = request.WorkId, - ApplicationId = request.ApplicationId, - TemplateDuration = request.TemplateDuration, - ShortDescription = request.ShortDescription, - FullDescription = request.FullDescription, - Solution = request.Solution, - NextRun = request.NextRun, - IsAgent = request.IsAgent, - AgentName = request.AgentName, - AgentTimeOutSec = request.AgentTimeOutSec, - AgentScript = request.AgentScript - }; - - //Добавляем настройки планировщика - foreach (var esppSchValue in request.Schedule.EsppSchValues) - { - applicationInWork.EsppSchValues.Add(new EsppSchValue - { - ApplicationsInWorkId = applicationInWork.Id, - TypeConfigId = esppSchValue.TypeConfigId, - TypeValueId = esppSchValue.TypeValueId - }); - } - - if (!await applicationsInWorkService.CreateAsync(applicationInWork) || !await applicationsInWorkService.CommitAsync()) - return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при записи нового задания на выполнение работ в базу данных" } })); - - logger.LogInformation($"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {applicationInWork.ShortDescription}, {applicationInWork.Solution}, {applicationInWork.NextRun}"); - - var locationUri = uriService.GetUri(ApiRoutes.Job.Get, ApiRoutes.Job.getParam, applicationInWork.Id); - - return Created(locationUri, new Response(mapper.Map(applicationInWork), true)); - } - - /// /// Получить список заданий на выполнение работ(ApplicationInWork) постранично /// @@ -114,7 +53,7 @@ namespace PARR.API.Controllers.V1 var paginationFilter = mapper.Map(paginationQuery); IQueryable query = applicationsInWorkService.Get() - .Include(t => t.Application).ThenInclude(t=>t!.ApplicationType) + .Include(t => t.Application).ThenInclude(t => t!.ApplicationType) .Include(t => t.Work) .Include(t => t.Templates) .OrderBy(t => t.ShortDescription); @@ -145,7 +84,7 @@ namespace PARR.API.Controllers.V1 var applicationInWork = await applicationsInWorkService.Get() .Include(t => t.Application).ThenInclude(t => t!.ApplicationType) .Include(t => t.Work) - .Include(t=>t.Templates) + .Include(t => t.Templates) .FirstOrDefaultAsync(t => t.Id == id); if (applicationInWork == null) @@ -156,8 +95,76 @@ namespace PARR.API.Controllers.V1 return Ok(new Response(response, true)); } + /// - /// Обновить задание на выполнение работ + /// Создать задание на выполнение работ (ApplicationInWork) + /// + /// + /// + [HttpPost(ApiRoutes.Job.Create)] + public async Task Create([FromBody] ApplicationInWorkRequest request) + { + var resultValidate = await validator.ValidateAsync(request); + + if (!resultValidate.IsValid) + return BadRequest(new Response(resultValidate.Errors)); + + 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})." } } + )); + + var applicationInWork = new ApplicationsInWork + { + Id = Guid.NewGuid(), + WorkId = request.WorkId, + ApplicationId = request.ApplicationId, + TemplateDuration = request.TemplateDuration, + ShortDescription = request.ShortDescription, + FullDescription = request.FullDescription, + Solution = request.Solution, + NextRun = request.NextRun, + IsAgent = request.IsAgent, + AgentName = request.AgentName, + AgentTimeOutSec = request.AgentTimeOutSec, + AgentScript = request.AgentScript + }; + + //Добавляем настройки планировщика + foreach (var esppSchValue in request.Schedule) + { + applicationInWork.EsppSchValues.Add(new EsppSchValue + { + ApplicationsInWorkId = applicationInWork.Id, + TypeConfigId = esppSchValue.TypeConfigId, + TypeValueId = esppSchValue.TypeValueId + }); + } + + if (!await applicationsInWorkService.CreateAsync(applicationInWork) || !await applicationsInWorkService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при созании задания на выполнение работ" } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {applicationInWork.Id}, {applicationInWork.ShortDescription}, {applicationInWork.Solution}, {applicationInWork.NextRun}"); + + + var createdApplicationInWork = await applicationsInWorkService.Get() + .Include(t => t.Application).ThenInclude(t => t!.ApplicationType) + .Include(t => t.Work) + .Include(t => t.Templates) + .FirstAsync(t => t.Id == applicationInWork.Id); + + var locationUri = uriService.GetUri(ApiRoutes.Job.Get, ApiRoutes.Job.getParam, createdApplicationInWork.Id); + + return Created(locationUri, new Response(mapper.Map(createdApplicationInWork), true)); + } + + + /// + /// Обновить задание на выполнение работ (ApplicationInWork) /// /// /// @@ -172,7 +179,7 @@ namespace PARR.API.Controllers.V1 var orig = await applicationsInWorkService.GetAsync(id); if (orig == null) - return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ. Не найдено задание на выполнение работ Id: {id}" } })); + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ. Не найдено задание с Id: {id}" } })); orig.WorkId = request.WorkId; orig.ApplicationId = request.ApplicationId; @@ -185,45 +192,72 @@ namespace PARR.API.Controllers.V1 orig.AgentName = request.AgentName; orig.AgentTimeOutSec = request.AgentTimeOutSec; orig.AgentScript = request.AgentScript; + orig.DateModified = DateTimeOffset.UtcNow; + + //обновляем планировщик + orig.EsppSchValues.Clear(); + request.Schedule.ForEach(item => + { + orig.EsppSchValues.Add(new EsppSchValue + { + ApplicationsInWorkId = orig.Id, + TypeConfigId = item.TypeConfigId, + TypeValueId = item.TypeValueId + }); + }); if (!await applicationsInWorkService.CommitAsync()) - return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка записи в базу данных изменений задания на выполнение работ." } })); + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при изменении задания на выполнение работ." } })); logger.LogInformation($"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," + $" {orig.WorkId}, {orig.ApplicationId}, {orig.TemplateDuration}, {orig.ShortDescription}," + $" {orig.FullDescription}, {orig.Solution}, {orig.NextRun}, {orig.IsAgent}, {orig.AgentName}, {orig.AgentTimeOutSec}, {orig.AgentScript}"); - return Ok(new Response(mapper.Map(orig), true)); + + var updatedApplicationInWork = await applicationsInWorkService.Get() + .Include(t => t.Application).ThenInclude(t => t!.ApplicationType) + .Include(t => t.Work) + .Include(t => t.Templates) + .FirstAsync(t => t.Id == orig.Id); + + return Ok(new Response(mapper.Map(updatedApplicationInWork), true)); } /// - /// Удалить задание на выполнение работ + /// Удалить задание на выполнение работ (только если нет связанных шаблонов) /// /// /// - //[HttpDelete(ApiRoutes.Job.Delete)] - //public async Task Delete([FromRoute] Guid id) - //{ - // var applicationsInWork = await applicationsInWorkService.GetAsync(id); + [HttpDelete(ApiRoutes.Job.Delete)] + public async Task Delete([FromRoute] Guid id) + { + var applicationsInWork = await applicationsInWorkService.Get() + .Include(t => t.Templates) + .FirstOrDefaultAsync(t => t.Id == id); - // if (applicationsInWork == null) - // return BadRequest(new Response(false, new List { new ErrorModel { - // Message = $"Ошибка при удалении задания на выполнение работ. Не найдено задание на выполнение работ Id: {id}" - // } })); + if (applicationsInWork == null) + return BadRequest(new Response(false, new List { new ErrorModel { + Message = $"Ошибка при удалении задания на выполнение работ. Не найдено задание на выполнение работ Id: {id}" + } })); - // if (!applicationsInWorkService.Delete(applicationsInWork) || !await applicationsInWorkService.CommitAsync()) - // return BadRequest(new Response(false, new List { new ErrorModel { - // Message = $"Ошибка при удалении задания на выполнение работ из базы данных" - // } })); + if (applicationsInWork.Templates.Any()) + return BadRequest(new Response(false, new List { new ErrorModel { + Message = $"Ошибка при удалении задания на выполнение работ. С данным заданием связаны шаблоны: {applicationsInWork.Templates.Count()} шт." + } })); - // logger.LogInformation($"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {applicationsInWork.Id},{applicationsInWork.WorkId}," + - // $" {applicationsInWork.ApplicationId}, {applicationsInWork.TemplateDuration}, {applicationsInWork.ShortDescription}," + - // $" {applicationsInWork.FullDescription}, {applicationsInWork.Solution}, {applicationsInWork.NextRun}, {applicationsInWork.IsAgent}," + - // $" {applicationsInWork.AgentName}, {applicationsInWork.AgentTimeOutSec}, {applicationsInWork.AgentScript}"); + if (!applicationsInWorkService.Delete(applicationsInWork) || !await applicationsInWorkService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { + Message = $"Ошибка при удалении задания на выполнение работ" + } })); - // return NoContent(); - //} + logger.LogInformation($"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {applicationsInWork.Id},{applicationsInWork.WorkId}," + + $" {applicationsInWork.ApplicationId}, {applicationsInWork.TemplateDuration}, {applicationsInWork.ShortDescription}," + + $" {applicationsInWork.FullDescription}, {applicationsInWork.Solution}, {applicationsInWork.NextRun}, {applicationsInWork.IsAgent}," + + $" {applicationsInWork.AgentName}, {applicationsInWork.AgentTimeOutSec}, {applicationsInWork.AgentScript}"); + + return NoContent(); + } } } diff --git a/PARR.API/Validators/ApplicationInWorkValidator.cs b/PARR.API/Validators/ApplicationInWorkValidator.cs index 9cc0b118..79a40ccf 100644 --- a/PARR.API/Validators/ApplicationInWorkValidator.cs +++ b/PARR.API/Validators/ApplicationInWorkValidator.cs @@ -22,34 +22,53 @@ namespace PARR.API.Validators RuleFor(t => t.TemplateDuration) - .NotNull().NotEmpty().WithMessage("Длительность данного задания на выполнение работ не может быть пустым") + .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)"); + .WithMessage("Значение не соответствует шаблону dd hh:mm:ss(7 00:00:00)"); RuleFor(t => t.ShortDescription) - .NotNull().NotEmpty().WithMessage("Краткое описание данного задания на выполнение работ не может быть пустым"); + .NotNull().NotEmpty();//.WithMessage("Краткое описание данного задания на выполнение работ не может быть пустым"); RuleFor(t => t.FullDescription) - .NotNull().NotEmpty().WithMessage("Подробное описание данного задания на выполнение работ не может быть пустым"); + .NotNull().NotEmpty();//.WithMessage("Подробное описание данного задания на выполнение работ не может быть пустым"); RuleFor(t => t.Solution) - .NotNull().NotEmpty().WithMessage("Решение данного задания на выполнение работ не может быть пустым"); + .NotNull().NotEmpty();//.WithMessage("Решение данного задания на выполнение работ не может быть пустым"); RuleFor(t => t.WorkId) .MustAsync(async (entity, value, c) => await IsWorkExist(entity)) - .WithMessage("У данного задания на выполнение работ указан несуществующий Id работы"); + .WithMessage("Указан несуществующий Id работы"); + //.WithMessage("У данного задания на выполнение работ указан несуществующий Id работы"); RuleFor(t => t.ApplicationId) .MustAsync(async (entity, value, c) => await IsApplicationExist(entity)) - .WithMessage("У данного задания на выполнение работ указан несуществующий Id программного обеспечения"); + .WithMessage("Указан несуществующий Id программного обеспечения"); + //.WithMessage("У данного задания на выполнение работ указан несуществующий Id программного обеспечения"); + + #region old schedule //Проверяем настройки планировщика - RuleFor(t => t.Schedule).NotNull().NotEmpty().WithMessage("Настройки планировщика задания на выполнение работ не могут быть пустыми"); + //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("Не удалось найти подходящую конфигруцию планировщика задания на выполнение работ"); + //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($"Настройки значений планировщика задания на выполнение работ не могут быть пустыми") @@ -65,15 +84,19 @@ namespace PARR.API.Validators // .NotNull().NotEmpty().WithMessage($"Настройки значений планировщика задания на выполнение работ не могут быть пустыми") // .Must((entity, value, c) => IsScheduleTypeValueIdExist(entity)) // .When(t => t.Schedule != null).WithMessage("Не удалось найти подходящую конфигруцию планировщика задания на выполнение работ"); + + #endregion } - private bool IsEsppSchValuesExist(ApplicationInWorkRequest request) + //private bool IsEsppSchValuesExist(ApplicationInWorkRequest request) + private bool IsEsppSchValuesExist(List listSchedule) { var configs = esppSchTypeConfigService.GetWithSchIncludes().ToList(); //Проверяем полученные Id конфигураций и Id конфигураций в базе - var typeConfigIdList = request.Schedule.EsppSchValues.Select(t => t.TypeConfigId); + 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; @@ -84,7 +107,7 @@ namespace PARR.API.Validators return false; //Теперь проверяем значения - foreach (var item in request.Schedule.EsppSchValues) + foreach (var item in listSchedule) { var curTypeConfig = configs.Where(t => t.Id == item.TypeConfigId).Single();