diff --git a/PARR.API/Contracts/V1/Requests/SubprocessRequest.cs b/PARR.API/Contracts/V1/Requests/SubprocessRequest.cs new file mode 100644 index 00000000..6b91387f --- /dev/null +++ b/PARR.API/Contracts/V1/Requests/SubprocessRequest.cs @@ -0,0 +1,9 @@ +namespace PARR.API.Contracts.V1.Requests +{ + public class SubprocessRequest + { + public required string Name { get; set; } + public int EsppId { get; set; } + public Guid ProcessId { get; set; } + } +} diff --git a/PARR.API/Controllers/V1/SubprocessController.cs b/PARR.API/Controllers/V1/SubprocessController.cs new file mode 100644 index 00000000..af6df569 --- /dev/null +++ b/PARR.API/Controllers/V1/SubprocessController.cs @@ -0,0 +1,203 @@ +using AutoMapper; +using FluentValidation; +using Microsoft.AspNetCore.Authorization; +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.Constants; +using PARR.DAL.DomainModels; +using PARR.DAL.Models; +using PARR.DAL.Services.Interfaces; + +namespace PARR.API.Controllers.V1 +{ + /// + /// Управление Подпроцессами + /// + [Authorize(Roles = ParrRoles.Administrator.Role)] + public class SubprocessController : BaseApiController + { + private readonly ILogger logger; + private readonly IMapper mapper; + private readonly ISubprocessService subprocessService; + private readonly IValidator validator; + private readonly IUriService uriService; + + public SubprocessController( + ILogger logger, + IMapper mapper, + ISubprocessService subprocessService, + IValidator validator, + IUriService uriService + ) + { + this.logger = logger; + this.mapper = mapper; + this.subprocessService = subprocessService; + this.validator = validator; + this.uriService = uriService; + } + + + /// + /// Создать подпроцесс + /// + /// + /// + [HttpPost(ApiRoutes.Subprocess.Create)] + public async Task Create([FromBody] SubprocessRequest request) + { + var resultValidate = await validator.ValidateAsync(request); + if (!resultValidate.IsValid) + return BadRequest(new Response(resultValidate.Errors)); + + var existName = await subprocessService.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 subprocess = new Subprocess + { + Id = Guid.NewGuid(), + Name = request.Name, + EsppId = request.EsppId, + ProcessId = request.ProcessId, + }; + + if (!await subprocessService.CreateAsync(subprocess) || !await subprocessService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при записи нового подпроцесса в базу данных" } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} добавил подпроцесс: {subprocess.Name}, {subprocess.EsppId}, {subprocess.ProcessId}"); + + var locationUri = uriService.GetUri(ApiRoutes.Subprocess.Get, ApiRoutes.Subprocess.getParam, subprocess.Id); + + return Created(locationUri, new Response(mapper.Map(subprocess), true)); + } + + + /// + /// Список подпроцессов постранично + /// + /// + /// + [HttpGet(ApiRoutes.Subprocess.GetAll)] + public async Task GetAll([FromQuery] PaginationQuery paginationQuery) + { + var paginationFilter = mapper.Map(paginationQuery); + + IQueryable query = subprocessService.Get() + .OrderBy(t => t.Name); + + var subprocesses = await subprocessService.GetPage(query, paginationFilter).ToListAsync(); + + if (!subprocesses.Any()) + return NoContent(); + + var subprocessesResponse = mapper.Map>(subprocesses); + var paginationResponse = new PagedResponse(subprocessesResponse, true).GetPaginatedProps(paginationFilter, query); + + return Ok(paginationResponse); + } + + + /// + /// Получить подпроцесс по id + /// + /// + /// + [HttpGet(ApiRoutes.Subprocess.Get)] + public async Task GetById([FromRoute] Guid id) + { + var subprocess = await subprocessService.Get() + .FirstOrDefaultAsync(t => t.Id == id); + + if (subprocess == null) + return NotFound(); + + var response = mapper.Map(subprocess); + + return Ok(new Response(response, true)); + } + + + /// + /// Получить связанные с подпроцессом ТНК + /// + /// + /// + [HttpGet(ApiRoutes.Subprocess.GetTnks)] + public async Task Get([FromRoute] Guid id) + { + var subprocess = await subprocessService.Get() + .Include(t => t.Tnks) + .FirstOrDefaultAsync(t => t.Id == id); + + if (subprocess == null) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Не найден подпроцесс с id: {id}" } })); + + var response = mapper.Map>(subprocess.Tnks.OrderBy(t => t.Name).ToList()); + + return Ok(new Response>(response, true)); + } + + + /// + /// Обновить подпроцесс + /// + /// + /// + /// + [HttpPut(ApiRoutes.Subprocess.Update)] + public async Task Update([FromRoute] Guid id, [FromBody] SubprocessRequest request) + { + var resultValidate = await validator.ValidateAsync(request); + if (!resultValidate.IsValid) + return BadRequest(new Response(resultValidate.Errors)); + + var orig = await subprocessService.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.ProcessId = request.ProcessId; + + if (!await subprocessService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка записи в базу данных изменений подпроцесса." } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} обновил подпроцесс: {orig.Id}, {orig.Name}, {orig.EsppId}, {orig.ProcessId}"); + + return Ok(new Response(mapper.Map(orig), true)); + } + + + /// + /// Удалить подпроцесс + /// + /// + /// + [HttpDelete(ApiRoutes.Subprocess.Delete)] + public async Task Delete([FromRoute] Guid id) + { + var subprocess = await subprocessService.GetAsync(id); + + if (subprocess == null) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении подпроцесса. Не найден подпроцесс Id: {id}" } })); + + if (!subprocessService.Delete(subprocess) || !await subprocessService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении подпроцесса из базы данных" } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} удалил подпроцесс: {subprocess.Id}, {subprocess.Name}, {subprocess.EsppId}, {subprocess.ProcessId}"); + + return NoContent(); + } + } +} diff --git a/PARR.API/Controllers/V1/TnkController.cs b/PARR.API/Controllers/V1/TnkController.cs index 09e6084f..7d58c368 100644 --- a/PARR.API/Controllers/V1/TnkController.cs +++ b/PARR.API/Controllers/V1/TnkController.cs @@ -1,21 +1,20 @@ using AutoMapper; using FluentValidation; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Cors.Infrastructure; 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.Base; 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.Constants; using PARR.DAL.DomainModels; -using PARR.DAL.Services.Interfaces; using PARR.DAL.Models; -using Microsoft.EntityFrameworkCore; -using PARR.API.Extensions; +using PARR.DAL.Services.Interfaces; namespace PARR.API.Controllers.V1 { @@ -74,7 +73,7 @@ namespace PARR.API.Controllers.V1 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}"); + logger.LogInformation($"Пользователь {User.Identity?.Name} добавил ТНК: {tnk.Name}, {tnk.EsppId}, {tnk.SubprocessId}"); var locationUri = uriService.GetUri(ApiRoutes.Tnk.Get, ApiRoutes.Tnk.getParam, tnk.Id); @@ -93,7 +92,6 @@ namespace PARR.API.Controllers.V1 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(); @@ -143,7 +141,7 @@ namespace PARR.API.Controllers.V1 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(); + var response = mapper.Map>(tnk.Works.OrderBy(t => t.Name).ToList()); return Ok(new Response>(response, true)); } diff --git a/PARR.API/Validators/SubprocessValidator.cs b/PARR.API/Validators/SubprocessValidator.cs new file mode 100644 index 00000000..062cf49d --- /dev/null +++ b/PARR.API/Validators/SubprocessValidator.cs @@ -0,0 +1,40 @@ +using FluentValidation; +using PARR.API.Contracts.V1.Requests; +using PARR.DAL.Services.Interfaces; + +namespace PARR.API.Validators +{ + public class SubprocessValidator : AbstractValidator + { + private readonly IProcessService processService; + private bool? isValid = null; + + public SubprocessValidator( + IProcessService processService + ) + { + this.processService = processService; + + RuleFor(t => t.Name).NotEmpty().NotNull().WithMessage("Имя подпроцесса не может быть пустым"); + + RuleFor(t => t.EsppId).NotEmpty().NotNull().WithMessage("EsppId не может быть пустым"); + + RuleFor(t => t.ProcessId).NotEmpty().NotNull().WithMessage("Подпроцесс должна быть связан с процессом. ProcessId не может быть пустым"); + + RuleFor(t => t.ProcessId) + .MustAsync(async (entity, value, c) => await IsProcessExist(entity)) + .WithMessage("У данного подпроцесса указан несуществующий Id процесса"); + } + + private async Task IsProcessExist(SubprocessRequest request) + { + //чтобы не делать 2 раза валидацию + if (isValid.HasValue) + return isValid.Value; + + isValid = await processService.GetAsync(request.ProcessId) != null; + + return isValid.Value; + } + } +}