From f435f80636fc2f76ae9a5362d0270d2233e06839 Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Wed, 4 Oct 2023 15:22:06 +1000 Subject: [PATCH] =?UTF-8?q?feat(api):=20=D0=9A=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=20=D1=83=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D0=B5=D0=B9=20=D1=80=D0=BE=D0=B1=D0=BE=D1=82=D0=B0.=20?= =?UTF-8?q?=D0=9A=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BF=D0=B5=D1=80=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8E=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20=D1=83=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=BD=D0=B5=D0=B9=20=D0=B8=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D0=B8=20=D1=80=D0=BE=D0=B1=D0=BE=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PARR.API/Contracts/V1/ApiRoutes.cs | 12 ++ .../Queries/RobotTemplateHistoryQuery.cs | 15 +++ .../Requests/RobotTemplateHistoryRequest.cs | 18 +++ .../V1/Responses/RobotHistoryLevelResponse.cs | 9 ++ .../Responses/RobotTemplateHistoryResponse.cs | 24 ++++ .../V1/RobotHistoryLevelController.cs | 42 +++++++ .../V1/RobotTemplateHistoryController.cs | 116 +++++++++++++++++- .../V1/TemplateRobotStatusController.cs | 27 ---- .../DomainToResponseProfile.cs | 7 ++ .../RobotTemplateHistoryRequestValidator.cs | 17 +++ 10 files changed, 258 insertions(+), 29 deletions(-) create mode 100644 PARR.API/Contracts/V1/Requests/Queries/RobotTemplateHistoryQuery.cs create mode 100644 PARR.API/Contracts/V1/Requests/RobotTemplateHistoryRequest.cs create mode 100644 PARR.API/Contracts/V1/Responses/RobotHistoryLevelResponse.cs create mode 100644 PARR.API/Contracts/V1/Responses/RobotTemplateHistoryResponse.cs create mode 100644 PARR.API/Controllers/V1/RobotHistoryLevelController.cs create mode 100644 PARR.API/Validators/RobotTemplateHistoryRequestValidator.cs diff --git a/PARR.API/Contracts/V1/ApiRoutes.cs b/PARR.API/Contracts/V1/ApiRoutes.cs index 78f5dd02..cc114b48 100644 --- a/PARR.API/Contracts/V1/ApiRoutes.cs +++ b/PARR.API/Contracts/V1/ApiRoutes.cs @@ -71,6 +71,12 @@ public const string templateId = "{templateId}"; } + public static class RobotTemplateHistory + { + public const string GetAll = Base + "/robot-template-histories/"; + public const string Create = Base + "/robot-template-histories/"; + } + public static class StatusTemplate { public const string GetAll = Base + "/template-statuses/"; @@ -86,6 +92,12 @@ public const string GetAll = Base + "/hosts/"; } + public static class RobotHistoryLevel + { + public const string GetAll = Base + "/robot-history-levels/"; + } + + //public static class Layer //{ // public const string GetAll = Base + "/layers/"; diff --git a/PARR.API/Contracts/V1/Requests/Queries/RobotTemplateHistoryQuery.cs b/PARR.API/Contracts/V1/Requests/Queries/RobotTemplateHistoryQuery.cs new file mode 100644 index 00000000..9e29df48 --- /dev/null +++ b/PARR.API/Contracts/V1/Requests/Queries/RobotTemplateHistoryQuery.cs @@ -0,0 +1,15 @@ +namespace PARR.API.Contracts.V1.Requests.Queries +{ + public class RobotTemplateHistoryQuery + { + /// + /// Фильтр по ИД шаблона + /// + public Guid? TemplateId { get; set; } + + /// + /// Фильтр по ИД серии + /// + public Guid? IdSeries { get; set; } + } +} diff --git a/PARR.API/Contracts/V1/Requests/RobotTemplateHistoryRequest.cs b/PARR.API/Contracts/V1/Requests/RobotTemplateHistoryRequest.cs new file mode 100644 index 00000000..c5c366ac --- /dev/null +++ b/PARR.API/Contracts/V1/Requests/RobotTemplateHistoryRequest.cs @@ -0,0 +1,18 @@ +namespace PARR.API.Contracts.V1.Requests +{ + public class RobotTemplateHistoryRequest + { + public int HistoryLevel { get; set; } + + public string? RobotMessage { get; set; } + + public string? EsppMessage { get; set; } + + public Guid TemplateId { get; set; } + + /// + /// ИД серии - идентификатор полного цикла выполнения роботом текущего задания. Если не передать, сгенерируется автоматически, в дальнейшем в рамках шагов по текущему заданию использовать его. + /// + public Guid? IdSeries { get; set; } + } +} diff --git a/PARR.API/Contracts/V1/Responses/RobotHistoryLevelResponse.cs b/PARR.API/Contracts/V1/Responses/RobotHistoryLevelResponse.cs new file mode 100644 index 00000000..f81e8f35 --- /dev/null +++ b/PARR.API/Contracts/V1/Responses/RobotHistoryLevelResponse.cs @@ -0,0 +1,9 @@ +namespace PARR.API.Contracts.V1.Responses +{ + public class RobotHistoryLevelResponse + { + public int Level { get; set; } + public required string Name { get; set; } + public required string Description { get; set; } + } +} diff --git a/PARR.API/Contracts/V1/Responses/RobotTemplateHistoryResponse.cs b/PARR.API/Contracts/V1/Responses/RobotTemplateHistoryResponse.cs new file mode 100644 index 00000000..7ea8ae96 --- /dev/null +++ b/PARR.API/Contracts/V1/Responses/RobotTemplateHistoryResponse.cs @@ -0,0 +1,24 @@ +namespace PARR.API.Contracts.V1.Responses +{ + public class RobotTemplateHistoryResponse + { + public Guid Id { get; set; } + + public DateTimeOffset Date { get; set; } + + public string? RobotMessage { get; set; } + + public string? EsppMessage { get; set; } + + public int TemplateStatusCode { get; set; } + + public Guid TemplateId { get; set; } + + public string TemplateName { get; set; } = string.Empty; + + public Guid IdSeries { get; set; } + + public RobotHistoryLevelResponse? Level { get; set; } + + } +} diff --git a/PARR.API/Controllers/V1/RobotHistoryLevelController.cs b/PARR.API/Controllers/V1/RobotHistoryLevelController.cs new file mode 100644 index 00000000..2dc3cdb9 --- /dev/null +++ b/PARR.API/Controllers/V1/RobotHistoryLevelController.cs @@ -0,0 +1,42 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using PARR.API.Contracts.V1; +using PARR.API.Contracts.V1.Responses; +using PARR.API.Contracts.V1.Responses.Base; +using PARR.API.Controllers.V1.Base; +using PARR.DAL.Services.Interfaces; + +namespace PARR.API.Controllers.V1 +{ + public class RobotHistoryLevelController : BaseApiController + { + private readonly IMapper mapper; + private readonly IRobotHistoryLevelService robotHistoryLevelService; + + public RobotHistoryLevelController( + IMapper mapper, + IRobotHistoryLevelService robotHistoryLevelService + ) + { + this.mapper = mapper; + this.robotHistoryLevelService = robotHistoryLevelService; + } + + /// + /// Получить список уровней истории работы робота + /// + /// + [HttpGet(ApiRoutes.RobotHistoryLevel.GetAll)] + public async Task GetAll() + { + var levels = await robotHistoryLevelService.Get() + .OrderBy(t => t.Level) + .ToListAsync(); + + var response = mapper.Map>(levels); + + return Ok(new Response>(response, true)); + } + } +} diff --git a/PARR.API/Controllers/V1/RobotTemplateHistoryController.cs b/PARR.API/Controllers/V1/RobotTemplateHistoryController.cs index 9d4215a4..372189c6 100644 --- a/PARR.API/Controllers/V1/RobotTemplateHistoryController.cs +++ b/PARR.API/Controllers/V1/RobotTemplateHistoryController.cs @@ -1,12 +1,124 @@ -using Microsoft.AspNetCore.Mvc; +using AutoMapper; +using FluentValidation; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using PARR.API.Contracts.V1; +using PARR.API.Contracts.V1.Requests; +using PARR.API.Contracts.V1.Requests.Queries; +using PARR.API.Contracts.V1.Responses; +using PARR.API.Contracts.V1.Responses.Base; using PARR.API.Controllers.V1.Base; +using PARR.API.Extensions; +using PARR.API.Services.Interfaces; +using PARR.DAL.DomainModels; +using PARR.DAL.Models; +using PARR.DAL.Services.Interfaces; namespace PARR.API.Controllers.V1 { public class RobotTemplateHistoryController : BaseApiController { - // get + private readonly IValidator validator; + private readonly ITemplateService templateService; + private readonly IRobotTemplateHistoryService historyService; + private readonly IMapper mapper; + private readonly IUriService uriService; + public RobotTemplateHistoryController( + IValidator validator, + ITemplateService templateService, + IRobotTemplateHistoryService historyService, + IMapper mapper, + IUriService uriService + ) + { + this.validator = validator; + this.templateService = templateService; + this.historyService = historyService; + this.mapper = mapper; + this.uriService = uriService; + } + + + /// + /// Получить историю робота шаблонов + /// + /// + /// + /// + [HttpGet(ApiRoutes.RobotTemplateHistory.GetAll)] + public async Task GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] RobotTemplateHistoryQuery filter) + { + var paginationFilter = mapper.Map(paginationQuery); + + IQueryable query = historyService.Get() + .Include(t => t.Template) + .Include(t => t.RobotHistoryLevel) + .OrderByDescending(t => t.DateCreated).ThenBy(t => t.IdSeries); + + if (filter.IdSeries != null) + query = query.Where(t => t.IdSeries == filter.IdSeries); + + if (filter.TemplateId != null) + query = query.Where(t => t.TemplateId == filter.TemplateId); + + + var history = await historyService.GetPage(query, paginationFilter).ToListAsync(); + + if (!history.Any()) + return NoContent(); + + var response = mapper.Map>(history); + var paginationResponse = new PagedResponse(response, true).GetPaginatedProps(paginationFilter, query); + + return Ok(paginationResponse); + } + + + /// + /// Добавить историю робота шаблонов + /// + /// + /// + [HttpPost(ApiRoutes.RobotTemplateHistory.Create)] + public async Task Create([FromBody] RobotTemplateHistoryRequest request) + { + var resultValidate = await validator.ValidateAsync(request); + if (!resultValidate.IsValid) + return BadRequest(new Response(resultValidate.Errors)); + + var template = await templateService.GetAsync(request.TemplateId); + + if (template == null) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Не найден шаблон с id: {request.TemplateId}" } })); + + if (request.IdSeries == null) + request.IdSeries = Guid.NewGuid(); + + var historyItem = new RobotTemplateHistory + { + Id = Guid.NewGuid(), + HistoryLevel = request.HistoryLevel, + RobotMessage = request.RobotMessage, + EsppMessage = request.EsppMessage, + TemplateId = request.TemplateId, + TemplateStatusCode = template.StatusCode, + IdSeries = request.IdSeries.Value + }; + + if (!await historyService.CreateAsync(historyItem) || !await historyService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при добавлении записи в историю" } })); + + var createdObj = await historyService.Get() + .Include(t => t.Template) + .Include(t => t.RobotHistoryLevel) + .FirstOrDefaultAsync(t => t.Id == historyItem.Id); + + var response = mapper.Map(createdObj); + var createdUri = uriService.GetAllUri(ApiRoutes.RobotTemplateHistory.GetAll) + $"?{nameof(RobotTemplateHistoryQuery.IdSeries)}={createdObj!.IdSeries}"; + + return Created(createdUri, new Response(response, true)); + } } } diff --git a/PARR.API/Controllers/V1/TemplateRobotStatusController.cs b/PARR.API/Controllers/V1/TemplateRobotStatusController.cs index 56ecf3f0..6a5e4961 100644 --- a/PARR.API/Controllers/V1/TemplateRobotStatusController.cs +++ b/PARR.API/Controllers/V1/TemplateRobotStatusController.cs @@ -75,33 +75,6 @@ namespace PARR.API.Controllers.V1 // изменение статуса templateService.ChangeRobotStatus(enumStatus, ref template); - //switch (request.Code) - //{ - // case (int)RobotStatusEnum.InProgress: - // template.RobotAttemptsNumber++; - // template.RobotStatusCode = request.Code; - // template.RobotLastStatusUpdated = DateTimeOffset.UtcNow; - // break; - // case (int)RobotStatusEnum.Error: - // template.RobotStatusCode = request.Code; - // break; - // case (int)RobotStatusEnum.Complete: - // template.RobotStatusCode = request.Code; - // template.RobotLastStatusUpdated = DateTimeOffset.UtcNow; - // break; - // case (int)RobotStatusEnum.Wait: - // template.RobotStatusCode = request.Code; - // template.RobotLastStatusUpdated = null; - // template.RobotAttemptsNumber = 0; - // break; - // default: - // break; - //} - - - - - if (!await templateService.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при изменении статуса шаблону {templateId}" } })); diff --git a/PARR.API/MappingProfiles/DomainToResponseProfile.cs b/PARR.API/MappingProfiles/DomainToResponseProfile.cs index 5a8fc9a9..2232f622 100644 --- a/PARR.API/MappingProfiles/DomainToResponseProfile.cs +++ b/PARR.API/MappingProfiles/DomainToResponseProfile.cs @@ -85,6 +85,13 @@ namespace PARR.API.MappingProfiles CreateMap(); + CreateMap(); + + CreateMap() + .ForMember(d => d.Level, o => o.MapFrom(s => s.RobotHistoryLevel)) + .ForMember(d => d.Date, o => o.MapFrom(s => s.DateCreated)) + .ForMember(d => d.TemplateName, o => o.MapFrom(s => s.Template!.Name)); + } } } diff --git a/PARR.API/Validators/RobotTemplateHistoryRequestValidator.cs b/PARR.API/Validators/RobotTemplateHistoryRequestValidator.cs new file mode 100644 index 00000000..93be9fbf --- /dev/null +++ b/PARR.API/Validators/RobotTemplateHistoryRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using PARR.API.Contracts.V1.Requests; +using PARR.DAL.Contracts; + +namespace PARR.API.Validators +{ + public class RobotTemplateHistoryRequestValidator : AbstractValidator + { + public RobotTemplateHistoryRequestValidator() + { + var levels = new List { (int)RobotHistoryLevelEnum.Start, (int)RobotHistoryLevelEnum.Inforamtion, (int)RobotHistoryLevelEnum.Error, (int)RobotHistoryLevelEnum.Complete, (int)RobotHistoryLevelEnum.Breake }; + RuleFor(r => r.HistoryLevel).Must(t => levels.Contains(t)).WithMessage($"Допустимые значения: {string.Join(", ", levels)}"); + + RuleFor(r => r.TemplateId).NotNull().NotEmpty(); + } + } +}