From 563f56b7705e4481166e50a91d5ada3b4c9d0aef Mon Sep 17 00:00:00 2001 From: Mikhail Kuznetsov Date: Wed, 6 Mar 2024 14:09:59 +1000 Subject: [PATCH] =?UTF-8?q?feat(api):=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=20TnkController+=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=B2=D1=85=D0=BE=D0=B4=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PARR.API/Contracts/V1/Requests/TnkRequest.cs | 9 + PARR.API/Controllers/V1/TnkController.cs | 205 +++++++++++++++++++ PARR.API/Controllers/V1/WorkController.cs | 4 +- PARR.API/Validators/TnkRequestValidator.cs | 40 ++++ PARR.API/Validators/WorkRequestValidator.cs | 2 +- 5 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 PARR.API/Contracts/V1/Requests/TnkRequest.cs create mode 100644 PARR.API/Controllers/V1/TnkController.cs create mode 100644 PARR.API/Validators/TnkRequestValidator.cs diff --git a/PARR.API/Contracts/V1/Requests/TnkRequest.cs b/PARR.API/Contracts/V1/Requests/TnkRequest.cs new file mode 100644 index 00000000..46ba6884 --- /dev/null +++ b/PARR.API/Contracts/V1/Requests/TnkRequest.cs @@ -0,0 +1,9 @@ +namespace PARR.API.Contracts.V1.Requests +{ + public class TnkRequest + { + public required string Name { get; set; } + public int EsppId { get; set; } + public Guid SubprocessId { get; set; } + } +} diff --git a/PARR.API/Controllers/V1/TnkController.cs b/PARR.API/Controllers/V1/TnkController.cs new file mode 100644 index 00000000..09e6084f --- /dev/null +++ b/PARR.API/Controllers/V1/TnkController.cs @@ -0,0 +1,205 @@ +using AutoMapper; +using FluentValidation; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors.Infrastructure; +using Microsoft.AspNetCore.Mvc; +using PARR.API.Contracts.V1; +using PARR.API.Contracts.V1.Requests; +using PARR.API.Contracts.V1.Requests.Queries; +using PARR.API.Contracts.V1.Responses.Base; +using PARR.API.Contracts.V1.Responses; +using PARR.API.Controllers.V1.Base; +using PARR.API.Services.Interfaces; +using PARR.Constants; +using PARR.DAL.DomainModels; +using PARR.DAL.Services.Interfaces; +using PARR.DAL.Models; +using Microsoft.EntityFrameworkCore; +using PARR.API.Extensions; + +namespace PARR.API.Controllers.V1 +{ + /// + /// Управление ТНК + /// + [Authorize(Roles = ParrRoles.Administrator.Role)] + public class TnkController : BaseApiController + { + private readonly ILogger logger; + private readonly IMapper mapper; + private readonly ITnkService tnkService; + private readonly IValidator validator; + private readonly IUriService uriService; + + public TnkController( + ILogger logger, + IMapper mapper, + ITnkService tnkService, + IValidator validator, + IUriService uriService + ) + { + this.logger = logger; + this.mapper = mapper; + this.tnkService = tnkService; + this.validator = validator; + this.uriService = uriService; + } + + + /// + /// Создать ТНК + /// + /// + /// + [HttpPost(ApiRoutes.Tnk.Create)] + public async Task Create([FromBody] TnkRequest request) + { + var resultValidate = await validator.ValidateAsync(request); + if (!resultValidate.IsValid) + return BadRequest(new Response(resultValidate.Errors)); + + var existName = await tnkService.Get().FirstOrDefaultAsync(t => t.Name == request.Name); + if (existName != null) + return BadRequest(new Response(false, new List { new ErrorModel { FieldName = nameof(request.Name), Message = $"Вид работы с именем \"{request.Name}\" уже существует." } })); + + var tnk = new Tnk + { + Id = Guid.NewGuid(), + Name = request.Name, + EsppId = request.EsppId, + SubprocessId = request.SubprocessId, + }; + + if (!await tnkService.CreateAsync(tnk) || !await tnkService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при записи новой ТНК в базу данных" } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} добавил вид работ: {tnk.Name}, {tnk.EsppId}, {tnk.SubprocessId}"); + + var locationUri = uriService.GetUri(ApiRoutes.Tnk.Get, ApiRoutes.Tnk.getParam, tnk.Id); + + return Created(locationUri, new Response(mapper.Map(tnk), true)); + } + + + /// + /// Список ТНК постранично + /// + /// + /// + [HttpGet(ApiRoutes.Tnk.GetAll)] + public async Task GetAll([FromQuery] PaginationQuery paginationQuery) + { + var paginationFilter = mapper.Map(paginationQuery); + + IQueryable query = tnkService.Get() + //.Include(t=>t.Subprocess).ThenInclude(t=>t.Process) + .OrderBy(t => t.Name); + + var tnks = await tnkService.GetPage(query, paginationFilter).ToListAsync(); + + if (!tnks.Any()) + return NoContent(); + + var tnkResponse = mapper.Map>(tnks); + var paginationResponse = new PagedResponse(tnkResponse, true).GetPaginatedProps(paginationFilter, query); + + return Ok(paginationResponse); + } + + + /// + /// Получить ТНК по id + /// + /// + /// + [HttpGet(ApiRoutes.Tnk.Get)] + public async Task GetById([FromRoute] Guid id) + { + var tnk = await tnkService.Get() + .FirstOrDefaultAsync(t => t.Id == id); + + if (tnk == null) + return NotFound(); + + var response = mapper.Map(tnk); + + return Ok(new Response(response, true)); + } + + + /// + /// Получить связанные с ТНК работы + /// + /// + /// + [HttpGet(ApiRoutes.Tnk.GetWorks)] + public async Task Get([FromRoute] Guid id) + { + var tnk = await tnkService.Get() + .Include(w => w.Works) + .FirstOrDefaultAsync(t => t.Id == id); + + if (tnk == null) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Не найдена ТНК с id: {id}" } })); + + var response = mapper.Map>(tnk.Works.OrderBy(t=>t.Name).ToList());//Roles.Select(t => t.Role)).OrderBy(t => t.Description).ToList(); + + return Ok(new Response>(response, true)); + } + + + /// + /// Обновить ТНК + /// + /// + /// + /// + [HttpPut(ApiRoutes.Tnk.Update)] + public async Task Update([FromRoute] Guid id, [FromBody] TnkRequest request) + { + var resultValidate = await validator.ValidateAsync(request); + if (!resultValidate.IsValid) + return BadRequest(new Response(resultValidate.Errors)); + + var orig = await tnkService.Get() + .FirstOrDefaultAsync(t => t.Id == id); + + if (orig == null) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при изменении ТНК. Не найдена ТНК Id: {id}" } })); + + orig.Name = request.Name; + orig.EsppId = request.EsppId; + orig.SubprocessId = request.SubprocessId; + + if (!await tnkService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка записи в базу данных изменений ТНК." } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} обновил ТНК: {orig.Id}, {orig.Name}, {orig.EsppId}, {orig.SubprocessId}"); + + return Ok(new Response(mapper.Map(orig), true)); + } + + + /// + /// Удалить ТНК + /// + /// + /// + [HttpDelete(ApiRoutes.Tnk.Delete)] + public async Task Delete([FromRoute] Guid id) + { + var tnk = await tnkService.GetAsync(id); + + if (tnk == null) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении ТНК. Не найдена ТНК Id: {id}" } })); + + if (!tnkService.Delete(tnk) || !await tnkService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении ТНК из базы данных" } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} удалил ТНК: {tnk.Id}, {tnk.Name}, {tnk.EsppId}, {tnk.SubprocessId}"); + + return NoContent(); + } + } +} diff --git a/PARR.API/Controllers/V1/WorkController.cs b/PARR.API/Controllers/V1/WorkController.cs index 8ba3b89e..d21a0a20 100644 --- a/PARR.API/Controllers/V1/WorkController.cs +++ b/PARR.API/Controllers/V1/WorkController.cs @@ -143,7 +143,7 @@ namespace PARR.API.Controllers.V1 .FirstOrDefaultAsync(t => t.Id == 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.Name = request.Name; orig.EsppId = request.EsppId; @@ -169,7 +169,7 @@ namespace PARR.API.Controllers.V1 var work = await workService.GetAsync(id); if (work == 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}" } })); if (!workService.Delete(work) || !await workService.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении вида работ." } })); diff --git a/PARR.API/Validators/TnkRequestValidator.cs b/PARR.API/Validators/TnkRequestValidator.cs new file mode 100644 index 00000000..327ac90b --- /dev/null +++ b/PARR.API/Validators/TnkRequestValidator.cs @@ -0,0 +1,40 @@ +using FluentValidation; +using PARR.API.Contracts.V1.Requests; +using PARR.DAL.Services.Interfaces; + +namespace PARR.API.Validators +{ + public class TnkRequestValidator : AbstractValidator + { + private readonly ISubprocessService subprocessService; + private bool? isValid = null; + + public TnkRequestValidator( + ISubprocessService subprocessService + ) + { + this.subprocessService = subprocessService; + + RuleFor(t => t.Name).NotEmpty().NotNull().WithMessage("Имя ТНК не может быть пустым"); + + RuleFor(t => t.EsppId).NotEmpty().NotNull().WithMessage("EsppId не может быть пустым"); + + RuleFor(t => t.SubprocessId).NotEmpty().NotNull().WithMessage("ТНК должна быть связана с подпроцессом. SubprocessId не может быть пустым"); + + RuleFor(t => t.SubprocessId) + .MustAsync(async (entity, value, c) => await IsSubprocessExist(entity)) + .WithMessage("У данной ТНК указан несуществующий Id подпроцесса"); + } + + private async Task IsSubprocessExist(TnkRequest request) + { + //чтобы не делать 2 раза валидацию + if (isValid.HasValue) + return isValid.Value; + + isValid = await subprocessService.GetAsync(request.SubprocessId) != null; + + return isValid.Value; + } + } +} diff --git a/PARR.API/Validators/WorkRequestValidator.cs b/PARR.API/Validators/WorkRequestValidator.cs index e0161c55..f31601ed 100644 --- a/PARR.API/Validators/WorkRequestValidator.cs +++ b/PARR.API/Validators/WorkRequestValidator.cs @@ -24,7 +24,7 @@ namespace PARR.API.Validators RuleFor(t => t.TnkId) .MustAsync(async (entity, value, c) => await IsTnkExist(entity)) - .WithMessage("У данной работы указан не существующий Id ТНК"); + .WithMessage("У данной работы указан несуществующий Id ТНК"); } private async Task IsTnkExist(WorkRequest request)