diff --git a/PARR.API/Contracts/V1/ApiRoutes.cs b/PARR.API/Contracts/V1/ApiRoutes.cs index b801ff53..d0436b9c 100644 --- a/PARR.API/Contracts/V1/ApiRoutes.cs +++ b/PARR.API/Contracts/V1/ApiRoutes.cs @@ -222,6 +222,66 @@ namespace PARR.API.Contracts.V1 public const string getParam = "{id}"; } + #endregion + + + #region TNK + + public static class Process + { + public const string GetAll = Base + "/processes/"; + public const string Get = Base + "/processes/" + getParam; + + public const string GetSubprcesses = Base + "/processes/" + getParam + "/subprocesses"; + + public const string Delete = Base + "/processes/" + getParam; + public const string Create = Base + "/processes/"; + public const string Update = Base + "/processes/" + getParam; + + public const string getParam = "{id}"; + } + + public static class Subprocess + { + public const string GetAll = Base + "/subprocesses/"; + public const string Get = Base + "/subprocesses/" + getParam; + + public const string GetTnks = Base + "/subprocesses/" + getParam + "/tnks"; + + public const string Delete = Base + "/subprocesses/" + getParam; + public const string Create = Base + "/subprocesses/"; + public const string Update = Base + "/subprocesses/" + getParam; + + public const string getParam = "{id}"; + } + + public static class Tnk + { + public const string GetAll = Base + "/tnks/"; + public const string Get = Base + "/tnks/" + getParam; + + public const string GetWorks = Base + "/tnks/" + getParam + "/works"; + + public const string Delete = Base + "/tnks/" + getParam; + public const string Create = Base + "/tnks/"; + public const string Update = Base + "/tnks/" + getParam; + + public const string getParam = "{id}"; + } + + public static class Work + { + public const string GetAll = Base + "/works/"; + public const string Get = Base + "/works/" + getParam; + public const string Delete = Base + "/works/" + getParam; + public const string Create = Base + "/works/"; + public const string Update = Base + "/works/" + getParam; + + public const string getParam = "{id}"; + } + + + #endregion } diff --git a/PARR.API/Contracts/V1/Requests/WorkRequest.cs b/PARR.API/Contracts/V1/Requests/WorkRequest.cs new file mode 100644 index 00000000..836d1d31 --- /dev/null +++ b/PARR.API/Contracts/V1/Requests/WorkRequest.cs @@ -0,0 +1,9 @@ +namespace PARR.API.Contracts.V1.Requests +{ + public class WorkRequest + { + public required string Name { get; set; } + public int EsppId { get; set; } + public Guid TnkId { get; set; } + } +} diff --git a/PARR.API/Controllers/V1/WorkController.cs b/PARR.API/Controllers/V1/WorkController.cs new file mode 100644 index 00000000..8ba3b89e --- /dev/null +++ b/PARR.API/Controllers/V1/WorkController.cs @@ -0,0 +1,183 @@ +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 WorkController : BaseApiController + { + private readonly ILogger logger; + private readonly IMapper mapper; + private readonly IWorkService workService; + private readonly IValidator validator; + private readonly IUriService uriService; + + public WorkController( + ILogger logger, + IMapper mapper, + IWorkService workService, + IValidator validator, + IUriService uriService + ) + { + this.logger = logger; + this.mapper = mapper; + this.workService = workService; + this.validator = validator; + this.uriService = uriService; + } + + + /// + /// Список видов работ постранично + /// + /// + /// + [HttpGet(ApiRoutes.Work.GetAll)] + public async Task GetAll([FromQuery] PaginationQuery paginationQuery) + { + var paginationFilter = mapper.Map(paginationQuery); + + IQueryable query = workService.Get() + .OrderBy(t => t.Name); + + var works = await workService.GetPage(query, paginationFilter).ToListAsync(); + + if (!works.Any()) + return NoContent(); + + var workResponse = mapper.Map>(works); + var paginationResponse = new PagedResponse(workResponse, true).GetPaginatedProps(paginationFilter, query); + + return Ok(paginationResponse); + } + + + /// + /// Создать вид работы + /// + /// + /// + [HttpPost(ApiRoutes.Work.Create)] + public async Task Create([FromBody] WorkRequest request) + { + var resultValidate = await validator.ValidateAsync(request); + if (!resultValidate.IsValid) + return BadRequest(new Response(resultValidate.Errors)); + + var existName = await workService.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 work = new Work + { + Id = Guid.NewGuid(), + Name = request.Name, + EsppId = request.EsppId, + TnkId = request.TnkId, + }; + + if (!await workService.CreateAsync(work) || !await workService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при создании вида работ." } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} добавил вид работ: {work.Name}, {work.EsppId}, {work.TnkId}"); + + var locationUri = uriService.GetUri(ApiRoutes.Work.Get, ApiRoutes.Work.getParam, work.Id); + + return Created(locationUri, new Response(mapper.Map(work), true)); + } + + + /// + /// Получить работу по id + /// + /// + /// + [HttpGet(ApiRoutes.Work.Get)] + public async Task GetById([FromRoute] Guid id) + { + var work = await workService.Get() + .FirstOrDefaultAsync(t => t.Id == id); + + if (work == null) + return NotFound(); + + var response = mapper.Map(work); + + return Ok(new Response(response, true)); + } + + + /// + /// Обновить вид работ + /// + /// + /// + /// + [HttpPut(ApiRoutes.Work.Update)] + public async Task Update([FromRoute] Guid id, [FromBody] WorkRequest request) + { + var resultValidate = await validator.ValidateAsync(request); + if (!resultValidate.IsValid) + return BadRequest(new Response(resultValidate.Errors)); + + var orig = await workService.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.TnkId = request.TnkId; + + if (!await workService.CommitAsync()) + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка записи в базу данных изменений вида работ." } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} обновил работу: {orig.Id}, {orig.Name}, {orig.EsppId}, {orig.TnkId}"); + + return Ok(new Response(mapper.Map(orig), true)); + } + + + /// + /// Удалить вид работ + /// + /// + /// + [HttpDelete(ApiRoutes.Work.Delete)] + public async Task Delete([FromRoute] Guid id) + { + var work = await workService.GetAsync(id); + + if (work == null) + 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 = $"Ошибка при удалении вида работ." } })); + + logger.LogInformation($"Пользователь {User.Identity?.Name} удалил вид работ: {work.Id}, {work.Name}, {work.EsppId}, {work.TnkId}"); + + return NoContent(); + } + + } +} diff --git a/PARR.API/Validators/WorkRequestValidator.cs b/PARR.API/Validators/WorkRequestValidator.cs new file mode 100644 index 00000000..e0161c55 --- /dev/null +++ b/PARR.API/Validators/WorkRequestValidator.cs @@ -0,0 +1,42 @@ +using FluentValidation; +using PARR.API.Contracts.V1.Requests; +using PARR.DAL.Services.Interfaces; + +namespace PARR.API.Validators +{ + public class WorkRequestValidator : AbstractValidator + { + private readonly ITnkService tnkService; + + private bool? isValid = null; + + public WorkRequestValidator( + ITnkService tnkService + ) + { + this.tnkService = tnkService; + + RuleFor(t => t.Name).NotEmpty().NotNull().WithMessage("Имя работ не может быть пустым"); + + RuleFor(t => t.EsppId).NotEmpty().NotNull().WithMessage("EsppId не может быть пустым"); + + RuleFor(t => t.TnkId).NotEmpty().NotNull().WithMessage("Работа должна быть связана с ТНК. TnkId не может быть пустым"); + + RuleFor(t => t.TnkId) + .MustAsync(async (entity, value, c) => await IsTnkExist(entity)) + .WithMessage("У данной работы указан не существующий Id ТНК"); + } + + private async Task IsTnkExist(WorkRequest request) + { + //чтобы не делать 2 раза валидацию + if (isValid.HasValue) + return isValid.Value; + + isValid = await tnkService.GetAsync(request.TnkId) != null; + + return isValid.Value; + } + + } +}