From 6738a3059219eed29436b92f5cd3eb07e02f18bd Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 24 Jan 2024 09:21:07 +0500 Subject: [PATCH 1/9] =?UTF-8?q?=D0=92=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20wellOpera?= =?UTF-8?q?tion=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20=D0=B2=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=B2=D0=BA=D0=BE=D0=B9,=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC,=20=D0=B8=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=82=D0=BE=D0=BC...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/IWellOperationRepository.cs | 17 ++++- .../Repository/WellOperationRepository.cs | 73 ++++++++++++++++--- .../Controllers/WellOperationController.cs | 66 ++++++++++++----- 3 files changed, 125 insertions(+), 31 deletions(-) diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs index d1db155e..d6302726 100644 --- a/AsbCloudApp/Repositories/IWellOperationRepository.cs +++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs @@ -114,5 +114,20 @@ namespace AsbCloudApp.Repositories /// /// Task GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken); - } + + /// + /// Валидация данных + /// + /// + /// + bool Validate(IEnumerable wellOperations); + + /// + /// Валидация данных (проверка с базой) + /// + /// + /// + /// + Task ValidateWithDbAsync(IEnumerable wellOperations, CancellationToken cancellationToken); + } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index fb0a8c12..ba566bca 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -50,7 +50,7 @@ public class WellOperationRepository : IWellOperationRepository } var result = categories - .OrderBy(o => o.Name) + .OrderBy(o => o.Name) .Adapt>(); return result; @@ -89,14 +89,14 @@ public class WellOperationRepository : IWellOperationRepository } private async Task GetDateLastAssosiatedPlanOperationAsync( - int idWell, - DateTime? lessThenDate, - double timeZoneHours, + int idWell, + DateTime? lessThenDate, + double timeZoneHours, CancellationToken token) { - if (lessThenDate is null) + if (lessThenDate is null) return null; - + var currentDateOffset = lessThenDate.Value.ToUtcDateTimeOffset(timeZoneHours); var timeZoneOffset = TimeSpan.FromHours(timeZoneHours); @@ -187,7 +187,7 @@ public class WellOperationRepository : IWellOperationRepository public async Task GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken) { var timezone = wellService.GetTimezone(idWell); - + var query = db.WellOperations.Where(o => o.IdWell == idWell && o.IdType == idType); if (!await query.AnyAsync(cancellationToken)) @@ -195,7 +195,7 @@ public class WellOperationRepository : IWellOperationRepository var minDate = await query.MinAsync(o => o.DateStart, cancellationToken); var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken); - + return new DatesRangeDto { From = minDate.ToRemoteDateTime(timezone.Hours), @@ -306,12 +306,13 @@ public class WellOperationRepository : IWellOperationRepository DeltaDepth = g.Sum(o => o.DurationDepth), IdParent = parentRelationDictionary[g.Key].IdParent }); - + while (dtos.All(x => x.IdParent != null)) { dtos = dtos .GroupBy(o => o.IdParent!) - .Select(g => { + .Select(g => + { var idCategory = g.Key ?? int.MinValue; var category = parentRelationDictionary.GetValueOrDefault(idCategory); var newDto = new WellGroupOpertionDto @@ -330,6 +331,58 @@ public class WellOperationRepository : IWellOperationRepository return dtos; } + public async Task ValidateWithDbAsync(IEnumerable wellOperationDtos, CancellationToken token) + { + var firstOperation = wellOperationDtos + .FirstOrDefault(); + if (firstOperation is null) + return false; + + var request = new WellOperationRequest() + { + IdWell = firstOperation.IdWell, + OperationType = firstOperation.IdType, + }; + + var operationWithMaxDateStart = await BuildQuery(request) + .OrderByDescending(o => o.DateStart) + .FirstOrDefaultAsync(token); + + if (operationWithMaxDateStart is null) + return Validate(wellOperationDtos); + + var maxOperationDateStart = operationWithMaxDateStart.DateStart; + foreach (var dto in wellOperationDtos) + { + var currentOperationDateStart = dto.DateStart.ToUniversalTime(); + if (maxOperationDateStart!.AddMonths(3) < currentOperationDateStart) + return false; + + maxOperationDateStart = currentOperationDateStart; + } + return true; + } + + public bool Validate(IEnumerable wellOperationDtos) + { + var firstOperation = wellOperationDtos + .FirstOrDefault(); + if (firstOperation is null) + return false; + + var maxOperationDateStart = firstOperation.DateStart.ToUniversalTime(); + + foreach (var dto in wellOperationDtos) + { + var currentOperationDateStart = dto.DateStart.ToUniversalTime(); + if (maxOperationDateStart.AddMonths(3) < currentOperationDateStart) + return false; + + maxOperationDateStart = currentOperationDateStart; + } + return true; + } + /// public async Task InsertRangeAsync( IEnumerable wellOperationDtos, diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs index ae0c8b92..fa479f12 100644 --- a/AsbCloudWebApi/Controllers/WellOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellOperationController.cs @@ -1,7 +1,13 @@ using AsbCloudApp.Data; +using AsbCloudApp.Data.WellOperationImport; +using AsbCloudApp.Data.WellOperationImport.Options; +using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; +using AsbCloudApp.Services.WellOperationImport; +using AsbCloudDb.Model; +using AsbCloudInfrastructure; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -12,12 +18,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using AsbCloudApp.Data.WellOperationImport; -using AsbCloudApp.Services.WellOperationImport; -using AsbCloudApp.Data.WellOperationImport.Options; -using AsbCloudApp.Exceptions; -using AsbCloudDb.Model; -using AsbCloudInfrastructure; namespace AsbCloudWebApi.Controllers { @@ -39,8 +39,8 @@ namespace AsbCloudWebApi.Controllers private readonly IWellOperationExcelParser wellOperationGazpromKhantosExcelParser; private readonly IUserRepository userRepository; - public WellOperationController(IWellOperationRepository operationRepository, - IWellService wellService, + public WellOperationController(IWellOperationRepository operationRepository, + IWellService wellService, IWellOperationImportTemplateService wellOperationImportTemplateService, IWellOperationExportService wellOperationExportService, IWellOperationImportService wellOperationImportService, @@ -231,12 +231,15 @@ namespace AsbCloudWebApi.Controllers if (!await CanUserEditWellOperationsAsync(idWell, cancellationToken)) return Forbid(); - + wellOperation.IdWell = idWell; wellOperation.LastUpdateDate = DateTimeOffset.UtcNow; wellOperation.IdUser = User.GetUserId(); wellOperation.IdType = idType; + if (!await operationRepository.ValidateWithDbAsync(new[] { wellOperation }, cancellationToken)) + return this.ValidationBadRequest(nameof(wellOperation), "The date difference between the operations is more than 3 months"); + var result = await operationRepository.InsertRangeAsync(new[] { wellOperation }, cancellationToken); return Ok(result); @@ -278,7 +281,7 @@ namespace AsbCloudWebApi.Controllers await operationRepository.DeleteAsync(existingOperations.Select(o => o.Id), cancellationToken); } - + foreach (var wellOperation in wellOperations) { wellOperation.IdWell = idWell; @@ -287,11 +290,31 @@ namespace AsbCloudWebApi.Controllers wellOperation.IdType = idType; } + + if (!await Validate(wellOperations, deleteBeforeInsert, cancellationToken)) + return this.ValidationBadRequest(nameof(wellOperations), "The date difference between the operations is more than 3 months"); + var result = await operationRepository.InsertRangeAsync(wellOperations, cancellationToken); return Ok(result); } + + /// + /// Валидация данных перед вставкой / обновлением / импортом + /// + /// + /// + /// + /// + private async Task Validate(IEnumerable wellOperations, bool deleteBeforeInsert, CancellationToken cancellationToken) + { + if (deleteBeforeInsert) + return operationRepository.Validate(wellOperations); + else + return await operationRepository.ValidateWithDbAsync(wellOperations, cancellationToken); + } + /// /// Обновляет выбранную операцию на скважине /// @@ -308,7 +331,7 @@ namespace AsbCloudWebApi.Controllers { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); - + if (!await CanUserEditWellOperationsAsync(idWell, token)) return Forbid(); @@ -317,6 +340,9 @@ namespace AsbCloudWebApi.Controllers value.LastUpdateDate = DateTimeOffset.UtcNow; value.IdUser = User.GetUserId(); + if (!await operationRepository.ValidateWithDbAsync(new[] { value }, token)) + return this.ValidationBadRequest(nameof(value), "The date difference between the operations is more than 3 months"); + var result = await operationRepository.UpdateAsync(value, token) .ConfigureAwait(false); return Ok(result); @@ -336,7 +362,7 @@ namespace AsbCloudWebApi.Controllers { if (!await CanUserAccessToWellAsync(idWell, token)) return Forbid(); - + if (!await CanUserEditWellOperationsAsync(idWell, token)) return Forbid(); @@ -373,7 +399,7 @@ namespace AsbCloudWebApi.Controllers deleteBeforeInsert, cancellationToken); } - + /// /// Импорт плановых операций из excel (xlsx) файла. Стандартный заполненный шаблон /// @@ -393,7 +419,7 @@ namespace AsbCloudWebApi.Controllers { IdType = WellOperation.IdOperationTypePlan }; - + return ImportExcelFileAsync(idWell, files, options, (stream, _) => wellOperationDefaultExcelParser.Parse(stream, options), null, @@ -522,7 +548,7 @@ namespace AsbCloudWebApi.Controllers return this.ValidationBadRequest(nameof(files), "Требуется xlsx файл."); using Stream stream = file.OpenReadStream(); - + try { var sheet = parseMethod(stream, options); @@ -541,8 +567,8 @@ namespace AsbCloudWebApi.Controllers //TODO: очень быстрый костыль if (deleteBeforeInsert is not null && options.IdType == WellOperation.IdOperationTypeFact) { - return await InsertRangeAsync(idWell, options.IdType, - deleteBeforeInsert.Value, + return await InsertRangeAsync(idWell, options.IdType, + deleteBeforeInsert.Value, wellOperations, cancellationToken); } @@ -554,21 +580,21 @@ namespace AsbCloudWebApi.Controllers return this.ValidationBadRequest(nameof(files), ex.Message); } } - + private async Task CanUserAccessToWellAsync(int idWell, CancellationToken token) { int? idCompany = User.GetCompanyId(); return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token).ConfigureAwait(false); } - + private async Task CanUserEditWellOperationsAsync(int idWell, CancellationToken token) { var idUser = User.GetUserId(); if (!idUser.HasValue) return false; - + var well = await wellService.GetOrDefaultAsync(idWell, token); if (well is null) From f9504aea21bce37af2c7a4bc5619e2db77ce6206 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 24 Jan 2024 11:18:58 +0500 Subject: [PATCH 2/9] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20ValidateWithDbA?= =?UTF-8?q?sync?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repository/WellOperationRepository.cs | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index ba566bca..4f77a485 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -22,6 +22,8 @@ namespace AsbCloudInfrastructure.Repository; public class WellOperationRepository : IWellOperationRepository { private const string KeyCacheSections = "OperationsBySectionSummarties"; + private const int Gap = 90; + private readonly IAsbCloudDbContext db; private readonly IMemoryCache memoryCache; private readonly IWellService wellService; @@ -344,21 +346,31 @@ public class WellOperationRepository : IWellOperationRepository OperationType = firstOperation.IdType, }; - var operationWithMaxDateStart = await BuildQuery(request) - .OrderByDescending(o => o.DateStart) - .FirstOrDefaultAsync(token); + var entities = await BuildQuery(request) + .AsNoTracking() + .ToArrayAsync(token) + .ConfigureAwait(false); - if (operationWithMaxDateStart is null) + if (!entities.Any()) return Validate(wellOperationDtos); - var maxOperationDateStart = operationWithMaxDateStart.DateStart; - foreach (var dto in wellOperationDtos) - { - var currentOperationDateStart = dto.DateStart.ToUniversalTime(); - if (maxOperationDateStart!.AddMonths(3) < currentOperationDateStart) - return false; + var wellOperationsUnion = entities.Union(wellOperationDtos).OrderBy(o => o.DateStart).ToArray(); - maxOperationDateStart = currentOperationDateStart; + for(var i = 1; i < wellOperationsUnion.Count(); i++) + { + var prevOperation = wellOperationsUnion[i - 1]; + var currentOperation = wellOperationsUnion[i]; + + var prevOperationDateStart = prevOperation.DateStart.ToUniversalTime(); + var currentOperationDateStart = currentOperation.DateStart.ToUniversalTime(); + + var prevOperationDateEnd = prevOperation.DateStart.AddHours(prevOperation.DurationHours).ToUniversalTime(); + var currrentOperationDateEnd = currentOperation.DateStart.AddHours(currentOperation.DurationHours).ToUniversalTime(); + + if (currentOperation.Id == 0 && ((prevOperationDateStart.AddDays(Gap) < currentOperationDateStart) || (prevOperationDateEnd >= currrentOperationDateEnd))) + { + return false; + } } return true; } @@ -375,7 +387,7 @@ public class WellOperationRepository : IWellOperationRepository foreach (var dto in wellOperationDtos) { var currentOperationDateStart = dto.DateStart.ToUniversalTime(); - if (maxOperationDateStart.AddMonths(3) < currentOperationDateStart) + if (maxOperationDateStart.AddDays(Gap) < currentOperationDateStart) return false; maxOperationDateStart = currentOperationDateStart; From 011a479a4b1ad278d99de9d9f4942b74e900b817 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 25 Jan 2024 10:35:16 +0500 Subject: [PATCH 3/9] =?UTF-8?q?=D0=92=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B2=D1=81=D1=82=D0=B0=D0=B2=D0=BA=D0=B8=20/?= =?UTF-8?q?=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20+=20=D0=B8=D0=BD=D1=82=D0=B5=D0=B3=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=BE=D0=BD=D0=BD=D1=8B=D0=B5=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= =?UTF-8?q?=20(=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/IWellOperationRepository.cs | 5 +- .../Repository/WellOperationRepository.cs | 67 +++++----- .../Clients/IWellOperationClient.cs | 14 +++ .../WellOperationControllerTest.cs | 115 ++++++++++++++++++ .../Controllers/WellOperationController.cs | 13 +- 5 files changed, 173 insertions(+), 41 deletions(-) create mode 100644 AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs create mode 100644 AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs index d6302726..43a7a568 100644 --- a/AsbCloudApp/Repositories/IWellOperationRepository.cs +++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs @@ -2,6 +2,7 @@ using AsbCloudApp.Requests; using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Threading; using System.Threading.Tasks; @@ -120,7 +121,7 @@ namespace AsbCloudApp.Repositories /// /// /// - bool Validate(IEnumerable wellOperations); + IEnumerable Validate(IEnumerable wellOperations); /// /// Валидация данных (проверка с базой) @@ -128,6 +129,6 @@ namespace AsbCloudApp.Repositories /// /// /// - Task ValidateWithDbAsync(IEnumerable wellOperations, CancellationToken cancellationToken); + IEnumerable ValidateWithDbAsync(IEnumerable wellOperations, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index 4f77a485..8a389e74 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -9,6 +9,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -333,12 +334,12 @@ public class WellOperationRepository : IWellOperationRepository return dtos; } - public async Task ValidateWithDbAsync(IEnumerable wellOperationDtos, CancellationToken token) + public IEnumerable ValidateWithDbAsync(IEnumerable wellOperationDtos, CancellationToken token) { var firstOperation = wellOperationDtos .FirstOrDefault(); if (firstOperation is null) - return false; + return Enumerable.Empty(); var request = new WellOperationRequest() { @@ -346,53 +347,51 @@ public class WellOperationRepository : IWellOperationRepository OperationType = firstOperation.IdType, }; - var entities = await BuildQuery(request) + var entities = BuildQuery(request) .AsNoTracking() - .ToArrayAsync(token) - .ConfigureAwait(false); + .ToArray(); - if (!entities.Any()) - return Validate(wellOperationDtos); + var wellOperationsUnion = entities.Union(wellOperationDtos).OrderBy(o => o.DateStart); - var wellOperationsUnion = entities.Union(wellOperationDtos).OrderBy(o => o.DateStart).ToArray(); + return Validate(wellOperationsUnion); + } - for(var i = 1; i < wellOperationsUnion.Count(); i++) + public IEnumerable Validate(IEnumerable wellOperationDtos) + { + var firstOperation = wellOperationDtos + .FirstOrDefault(); + if (firstOperation is null) + return Enumerable.Empty(); + + var validationResults = new List(); + + var wellOperations = wellOperationDtos.ToArray(); + for (var i = wellOperations.Count() - 1; i >= 1; i--) { - var prevOperation = wellOperationsUnion[i - 1]; - var currentOperation = wellOperationsUnion[i]; + var prevOperation = wellOperations[i - 1]; + var currentOperation = wellOperations[i]; var prevOperationDateStart = prevOperation.DateStart.ToUniversalTime(); var currentOperationDateStart = currentOperation.DateStart.ToUniversalTime(); var prevOperationDateEnd = prevOperation.DateStart.AddHours(prevOperation.DurationHours).ToUniversalTime(); - var currrentOperationDateEnd = currentOperation.DateStart.AddHours(currentOperation.DurationHours).ToUniversalTime(); - if (currentOperation.Id == 0 && ((prevOperationDateStart.AddDays(Gap) < currentOperationDateStart) || (prevOperationDateEnd >= currrentOperationDateEnd))) + if (prevOperationDateStart.AddDays(Gap) < currentOperationDateStart) { - return false; + validationResults.Add(new ValidationResult( + $"Разница дат между операциями не должна превышать 90 дней", + new[] { nameof(wellOperations) })); + } + + if (prevOperationDateEnd > currentOperationDateStart) + { + validationResults.Add(new ValidationResult( + $"Предыдущая операция не завершена", + new[] { nameof(wellOperations) })); } } - return true; - } - public bool Validate(IEnumerable wellOperationDtos) - { - var firstOperation = wellOperationDtos - .FirstOrDefault(); - if (firstOperation is null) - return false; - - var maxOperationDateStart = firstOperation.DateStart.ToUniversalTime(); - - foreach (var dto in wellOperationDtos) - { - var currentOperationDateStart = dto.DateStart.ToUniversalTime(); - if (maxOperationDateStart.AddDays(Gap) < currentOperationDateStart) - return false; - - maxOperationDateStart = currentOperationDateStart; - } - return true; + return validationResults; } /// diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs new file mode 100644 index 00000000..6192d306 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs @@ -0,0 +1,14 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMapPlan; +using AsbCloudApp.Requests; +using Refit; + +namespace AsbCloudWebApi.IntegrationTests.Clients; + +public interface IWellOperationClient +{ + private const string BaseRoute = "/api/wellOperation"; + + [Post(BaseRoute)] + Task> InsertRange(int idWell, [Body] IEnumerable dtos); +} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs new file mode 100644 index 00000000..17130b5e --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs @@ -0,0 +1,115 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.ProcessMapPlan; +using AsbCloudApp.Requests; +using AsbCloudDb.Model; +using AsbCloudDb.Model.ProcessMaps; +using AsbCloudWebApi.IntegrationTests.Clients; +using System.Net; +using Xunit; + +namespace AsbCloudWebApi.IntegrationTests.Controllers; + + +public class WellOperationControllerTest : BaseIntegrationTest +{ + private readonly int idWell = 4; + + private readonly WellOperationDto[] dtos = new WellOperationDto[] + { + new WellOperationDto() + { + + }, + new WellOperationDto() + { + + } + }; + + private IWellOperationClient wellOperationClient; + + public WellOperationControllerTest(WebAppFactoryFixture factory) + : base(factory) + { + wellOperationClient = factory.GetAuthorizedHttpClient(); + var rep = factory.Get + } + + /// + /// Успешное добавление операции с предварительной очисткой + /// + /// + [Fact] + public async Task InsertRangeWithDeleteBefore_returns_success() + { + ////arrange + //dbContext.WellOperations.Add(wellOperation); + //dbContext.SaveChanges(); + + //var request = new OperationStatRequest + //{ + // DateStartUTC = schedule.DrillStart.DateTime, + // DateEndUTC = schedule.DrillEnd.DateTime, + // DurationMinutesMin = 0, + // DurationMinutesMax = 5 + //}; + + //var dtoExpected = new SlipsStatDto + //{ + // DrillerName = $"{Data.Defaults.Drillers[0].Surname} {Data.Defaults.Drillers[0].Name} {Data.Defaults.Drillers[0].Patronymic}", + // WellCount = 1, + // SectionCaption = "Пилотный ствол", + // SlipsCount = 1, + // SlipsTimeInMinutes = (detectedOperation.DateEnd - detectedOperation.DateStart).TotalMinutes, + // SectionDepth = factWellOperation.DepthEnd - factWellOperation.DepthStart, + //}; + + ////act + //var response = await slipsTimeClient.GetAll(request); + + ////assert + //Assert.NotNull(response.Content); + //Assert.Single(response.Content); + + //var dtoActual = response.Content.First(); + //MatchHelper.Match(dtoExpected, dtoActual); + } + + /// + /// Успешное добавление операции без очистки + /// + /// + [Fact] + public async Task InsertRange_returns_success() { + //arrange + var dbset = dbContext.Set(); + dbset.RemoveRange(dbset); + dbContext.SaveChanges(); + + operationRepository.Validate(dtos); + + //act + var response = await wellOperationClient.InsertRange(idWell, dtos); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + /// + /// Неуспешное добавление операции с предварительной очисткой + /// + /// + [Fact] + public async Task InsertRangeWithDeleteBefore_returns_error() + { + } + + /// + /// Неуспешное добавление операции без очистки + /// + /// + [Fact] + public async Task InsertRange_returns_error() + { + } +} \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs index fa479f12..5c0039cc 100644 --- a/AsbCloudWebApi/Controllers/WellOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellOperationController.cs @@ -237,7 +237,8 @@ namespace AsbCloudWebApi.Controllers wellOperation.IdUser = User.GetUserId(); wellOperation.IdType = idType; - if (!await operationRepository.ValidateWithDbAsync(new[] { wellOperation }, cancellationToken)) + var validationResult = operationRepository.ValidateWithDbAsync(new[] { wellOperation }, cancellationToken); + if(validationResult.Any()) return this.ValidationBadRequest(nameof(wellOperation), "The date difference between the operations is more than 3 months"); var result = await operationRepository.InsertRangeAsync(new[] { wellOperation }, cancellationToken); @@ -291,7 +292,8 @@ namespace AsbCloudWebApi.Controllers } - if (!await Validate(wellOperations, deleteBeforeInsert, cancellationToken)) + var validationResult = Validate(wellOperations, deleteBeforeInsert, cancellationToken); + if (validationResult.Any()) return this.ValidationBadRequest(nameof(wellOperations), "The date difference between the operations is more than 3 months"); var result = await operationRepository.InsertRangeAsync(wellOperations, cancellationToken); @@ -307,12 +309,12 @@ namespace AsbCloudWebApi.Controllers /// /// /// - private async Task Validate(IEnumerable wellOperations, bool deleteBeforeInsert, CancellationToken cancellationToken) + private IEnumerable Validate(IEnumerable wellOperations, bool deleteBeforeInsert, CancellationToken cancellationToken) { if (deleteBeforeInsert) return operationRepository.Validate(wellOperations); else - return await operationRepository.ValidateWithDbAsync(wellOperations, cancellationToken); + return operationRepository.ValidateWithDbAsync(wellOperations, cancellationToken); } /// @@ -340,7 +342,8 @@ namespace AsbCloudWebApi.Controllers value.LastUpdateDate = DateTimeOffset.UtcNow; value.IdUser = User.GetUserId(); - if (!await operationRepository.ValidateWithDbAsync(new[] { value }, token)) + var validationResult = operationRepository.ValidateWithDbAsync(new[] { value }, token); + if (validationResult.Any()) return this.ValidationBadRequest(nameof(value), "The date difference between the operations is more than 3 months"); var result = await operationRepository.UpdateAsync(value, token) From ff208a6aa8a168d29f3341efd2a9aaf9bd4529f3 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 25 Jan 2024 15:56:34 +0500 Subject: [PATCH 4/9] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=8B=D0=B9=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=20(InsertRangeAsync)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BaseIntegrationTest.cs | 2 +- .../Clients/IWellOperationClient.cs | 9 +- .../WellOperationControllerTest.cs | 169 +++++++++++------- .../Data/Defaults.cs | 23 ++- .../WebAppFactoryFixture.cs | 3 +- 5 files changed, 133 insertions(+), 73 deletions(-) diff --git a/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs b/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs index d18c54bf..add2e07b 100644 --- a/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs +++ b/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs @@ -6,7 +6,7 @@ namespace AsbCloudWebApi.IntegrationTests; public abstract class BaseIntegrationTest : IClassFixture { - private readonly IServiceScope scope; + protected readonly IServiceScope scope; protected readonly IAsbCloudDbContext dbContext; diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs index 6192d306..43497d6c 100644 --- a/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs +++ b/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs @@ -1,14 +1,13 @@ using AsbCloudApp.Data; -using AsbCloudApp.Data.ProcessMapPlan; -using AsbCloudApp.Requests; using Refit; namespace AsbCloudWebApi.IntegrationTests.Clients; public interface IWellOperationClient { - private const string BaseRoute = "/api/wellOperation"; + private const string BaseRoute = "/api/well/{idWell}/wellOperations"; + + [Post(BaseRoute + "/{idType}/{deleteBeforeInsert}")] + Task> InsertRangeAsync(int idWell, int idType, bool deleteBeforeInsert, [Body] IEnumerable dtos); - [Post(BaseRoute)] - Task> InsertRange(int idWell, [Body] IEnumerable dtos); } \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs index 17130b5e..2651243f 100644 --- a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs +++ b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs @@ -1,8 +1,4 @@ using AsbCloudApp.Data; -using AsbCloudApp.Data.ProcessMapPlan; -using AsbCloudApp.Requests; -using AsbCloudDb.Model; -using AsbCloudDb.Model.ProcessMaps; using AsbCloudWebApi.IntegrationTests.Clients; using System.Net; using Xunit; @@ -12,104 +8,147 @@ namespace AsbCloudWebApi.IntegrationTests.Controllers; public class WellOperationControllerTest : BaseIntegrationTest { - private readonly int idWell = 4; + private static int idWell = 1; private readonly WellOperationDto[] dtos = new WellOperationDto[] - { - new WellOperationDto() - { + { + new WellOperationDto() + { + Id = 2, + IdWell = idWell, + IdType = 1, + DateStart = DateTimeOffset.Now, + CategoryInfo = "1", + CategoryName = "1", + Comment = "1", + Day = 1, + DepthEnd = 20, + DepthStart = 10, + DurationHours = 1, + IdCategory = 5000, + IdParentCategory = null, + IdPlan = null, + IdUser = 1, + IdWellSectionType = 1, + LastUpdateDate = DateTimeOffset.Now, + NptHours = 1, + WellSectionTypeName = null, + UserName = null + } + }; - }, + private readonly WellOperationDto[] dtosWithError = new WellOperationDto[] + { new WellOperationDto() { - + Id = 3, + IdWell = idWell, + IdType = 1, + DateStart = DateTimeOffset.Now, + CategoryInfo = "1", + CategoryName = "1", + Comment = "1", + Day = 1, + DepthEnd = 20, + DepthStart = 10, + DurationHours = 1, + IdCategory = 5000, + IdParentCategory = null, + IdPlan = null, + IdUser = 1, + IdWellSectionType = 1, + LastUpdateDate = DateTimeOffset.Now, + NptHours = 1, + WellSectionTypeName = null, + UserName = null + }, + new WellOperationDto() + { + Id = 4, + IdWell = idWell, + IdType = 1, + DateStart = DateTimeOffset.Now.AddDays(1000), + CategoryInfo = "1", + CategoryName = "1", + Comment = "1", + Day = 1, + DepthEnd = 20, + DepthStart = 10, + DurationHours = 1, + IdCategory = 5000, + IdParentCategory = null, + IdPlan = null, + IdUser = 1, + IdWellSectionType = 1, + LastUpdateDate = DateTimeOffset.Now, + NptHours = 1, + WellSectionTypeName = null, + UserName = null } }; private IWellOperationClient wellOperationClient; public WellOperationControllerTest(WebAppFactoryFixture factory) - : base(factory) - { + : base(factory) + { wellOperationClient = factory.GetAuthorizedHttpClient(); - var rep = factory.Get } /// - /// Успешное добавление операции с предварительной очисткой + /// Успешное добавление операций (с предварительной очисткой данных) /// /// [Fact] - public async Task InsertRangeWithDeleteBefore_returns_success() - { - ////arrange - //dbContext.WellOperations.Add(wellOperation); - //dbContext.SaveChanges(); + public async Task InsertRange_returns_success() + { + //act + var response = await wellOperationClient.InsertRangeAsync(idWell, 1, true, dtos); - //var request = new OperationStatRequest - //{ - // DateStartUTC = schedule.DrillStart.DateTime, - // DateEndUTC = schedule.DrillEnd.DateTime, - // DurationMinutesMin = 0, - // DurationMinutesMax = 5 - //}; + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } - //var dtoExpected = new SlipsStatDto - //{ - // DrillerName = $"{Data.Defaults.Drillers[0].Surname} {Data.Defaults.Drillers[0].Name} {Data.Defaults.Drillers[0].Patronymic}", - // WellCount = 1, - // SectionCaption = "Пилотный ствол", - // SlipsCount = 1, - // SlipsTimeInMinutes = (detectedOperation.DateEnd - detectedOperation.DateStart).TotalMinutes, - // SectionDepth = factWellOperation.DepthEnd - factWellOperation.DepthStart, - //}; - - ////act - //var response = await slipsTimeClient.GetAll(request); - - ////assert - //Assert.NotNull(response.Content); - //Assert.Single(response.Content); - - //var dtoActual = response.Content.First(); - //MatchHelper.Match(dtoExpected, dtoActual); - } /// - /// Успешное добавление операции без очистки + /// Неуспешное добавление операций (с предварительной очисткой данных) /// /// [Fact] - public async Task InsertRange_returns_success() { - //arrange - var dbset = dbContext.Set(); - dbset.RemoveRange(dbset); - dbContext.SaveChanges(); - - operationRepository.Validate(dtos); - + public async Task InsertRange_returns_error() + { //act - var response = await wellOperationClient.InsertRange(idWell, dtos); + var response = await wellOperationClient.InsertRangeAsync(idWell, 1, true, dtosWithError); + + //assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + /// + /// Успешное добавление операций (с предварительной очисткой данных) + /// + /// + [Fact] + public async Task InsertRangeWithDeleteBefore_returns_success() + { + //act + var response = await wellOperationClient.InsertRangeAsync(idWell, 1, false, dtos); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); } /// - /// Неуспешное добавление операции с предварительной очисткой + /// Неуспешное добавление операций (с предварительной очисткой данных) /// /// [Fact] public async Task InsertRangeWithDeleteBefore_returns_error() { - } + //act + var response = await wellOperationClient.InsertRangeAsync(idWell, 1, false, dtosWithError); - /// - /// Неуспешное добавление операции без очистки - /// - /// - [Fact] - public async Task InsertRange_returns_error() - { + //assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } } \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs b/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs index ddb7dbe7..fc36eb3f 100644 --- a/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs +++ b/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs @@ -14,7 +14,28 @@ namespace AsbCloudWebApi.IntegrationTests.Data Surname = "test" } }; - + + public static WellOperation[] WellOperations = new WellOperation[] + { + new() + { + Id = 2, + IdWell = 1, + IdType = 1, + DateStart = DateTimeOffset.UtcNow.AddDays(-1), + CategoryInfo = "1", + Comment = "1", + DepthEnd = 20, + DepthStart = 10, + DurationHours = 1, + IdCategory = 5000, + IdPlan = null, + IdUser = 1, + IdWellSectionType = 1, + LastUpdateDate = DateTimeOffset.UtcNow + } + }; + public static Deposit[] Deposits = new Deposit[] { new() { diff --git a/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs b/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs index a0111303..af7303b6 100644 --- a/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs +++ b/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs @@ -60,7 +60,8 @@ public class WebAppFactoryFixture : WebApplicationFactory, dbContext.AddRange(Data.Defaults.RelationsCompanyWell); dbContext.AddRange(Data.Defaults.Telemetries); dbContext.AddRange(Data.Defaults.Drillers); - await dbContext.SaveChangesAsync(); + dbContext.AddRange(Data.Defaults.WellOperations); + await dbContext.SaveChangesAsync(); } public new async Task DisposeAsync() From d4935b0e7b59a4530686bc8f271a1bf35591b486 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 25 Jan 2024 16:22:40 +0500 Subject: [PATCH 5/9] =?UTF-8?q?=D0=92=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=81=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=D0=BC=20yield?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repository/WellOperationRepository.cs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index 8a389e74..2e4e956a 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -339,7 +339,7 @@ public class WellOperationRepository : IWellOperationRepository var firstOperation = wellOperationDtos .FirstOrDefault(); if (firstOperation is null) - return Enumerable.Empty(); + yield break; var request = new WellOperationRequest() { @@ -353,7 +353,9 @@ public class WellOperationRepository : IWellOperationRepository var wellOperationsUnion = entities.Union(wellOperationDtos).OrderBy(o => o.DateStart); - return Validate(wellOperationsUnion); + var results = Validate(wellOperationsUnion); + foreach ( var result in results) + yield return result; } public IEnumerable Validate(IEnumerable wellOperationDtos) @@ -361,12 +363,10 @@ public class WellOperationRepository : IWellOperationRepository var firstOperation = wellOperationDtos .FirstOrDefault(); if (firstOperation is null) - return Enumerable.Empty(); + yield break; - var validationResults = new List(); - - var wellOperations = wellOperationDtos.ToArray(); - for (var i = wellOperations.Count() - 1; i >= 1; i--) + var wellOperations = wellOperationDtos.OrderBy(o => o.DateStart).ToArray(); + for (var i = 1; i < wellOperations.Length; i++) { var prevOperation = wellOperations[i - 1]; var currentOperation = wellOperations[i]; @@ -378,20 +378,18 @@ public class WellOperationRepository : IWellOperationRepository if (prevOperationDateStart.AddDays(Gap) < currentOperationDateStart) { - validationResults.Add(new ValidationResult( + yield return new ValidationResult( $"Разница дат между операциями не должна превышать 90 дней", - new[] { nameof(wellOperations) })); + new[] { nameof(wellOperations) }); } if (prevOperationDateEnd > currentOperationDateStart) { - validationResults.Add(new ValidationResult( + yield return new ValidationResult( $"Предыдущая операция не завершена", - new[] { nameof(wellOperations) })); + new[] { nameof(wellOperations) }); } } - - return validationResults; } /// From 672f78fca99461b65b5f25de51a5efe0644e8d52 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Thu, 25 Jan 2024 16:47:04 +0500 Subject: [PATCH 6/9] WellOperationRepository refactor ValidateWithDbAsync and Validate --- .../Repositories/IWellOperationRepository.cs | 2 +- .../Repository/WellOperationRepository.cs | 48 ++++++++++--------- .../Controllers/WellOperationController.cs | 12 ++--- AsbCloudWebApi/Extentions.cs | 24 ++++++++++ 4 files changed, 56 insertions(+), 30 deletions(-) diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs index 43a7a568..8cb313ac 100644 --- a/AsbCloudApp/Repositories/IWellOperationRepository.cs +++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs @@ -129,6 +129,6 @@ namespace AsbCloudApp.Repositories /// /// /// - IEnumerable ValidateWithDbAsync(IEnumerable wellOperations, CancellationToken cancellationToken); + Task> ValidateWithDbAsync(IEnumerable wellOperations, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index 2e4e956a..208e94ac 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -334,12 +334,13 @@ public class WellOperationRepository : IWellOperationRepository return dtos; } - public IEnumerable ValidateWithDbAsync(IEnumerable wellOperationDtos, CancellationToken token) + public async Task> ValidateWithDbAsync(IEnumerable wellOperationDtos, CancellationToken token) { var firstOperation = wellOperationDtos .FirstOrDefault(); + if (firstOperation is null) - yield break; + return Enumerable.Empty(); var request = new WellOperationRequest() { @@ -347,48 +348,49 @@ public class WellOperationRepository : IWellOperationRepository OperationType = firstOperation.IdType, }; - var entities = BuildQuery(request) + var entities = await BuildQuery(request) .AsNoTracking() - .ToArray(); + .ToArrayAsync(token); var wellOperationsUnion = entities.Union(wellOperationDtos).OrderBy(o => o.DateStart); var results = Validate(wellOperationsUnion); - foreach ( var result in results) - yield return result; + return results; } public IEnumerable Validate(IEnumerable wellOperationDtos) { - var firstOperation = wellOperationDtos - .FirstOrDefault(); - if (firstOperation is null) + var enumerator = wellOperationDtos.OrderBy(o => o.DateStart) + .GetEnumerator(); + + if (!enumerator.MoveNext()) yield break; - var wellOperations = wellOperationDtos.OrderBy(o => o.DateStart).ToArray(); - for (var i = 1; i < wellOperations.Length; i++) + var previous = enumerator.Current; + + while(enumerator.MoveNext()) { - var prevOperation = wellOperations[i - 1]; - var currentOperation = wellOperations[i]; + var current = enumerator.Current; + var previousDateStart = previous.DateStart.ToUniversalTime(); + var currentDateStart = current.DateStart.ToUniversalTime(); - var prevOperationDateStart = prevOperation.DateStart.ToUniversalTime(); - var currentOperationDateStart = currentOperation.DateStart.ToUniversalTime(); + var previousDateEnd = previous.DateStart.AddHours(previous.DurationHours).ToUniversalTime(); - var prevOperationDateEnd = prevOperation.DateStart.AddHours(prevOperation.DurationHours).ToUniversalTime(); - - if (prevOperationDateStart.AddDays(Gap) < currentOperationDateStart) + if (previousDateStart.AddDays(Gap) < currentDateStart) { yield return new ValidationResult( - $"Разница дат между операциями не должна превышать 90 дней", - new[] { nameof(wellOperations) }); + "Разница дат между операциями не должна превышать 90 дней", + new[] { nameof(wellOperationDtos) }); } - if (prevOperationDateEnd > currentOperationDateStart) + if (previousDateEnd > currentDateStart) { yield return new ValidationResult( - $"Предыдущая операция не завершена", - new[] { nameof(wellOperations) }); + "Предыдущая операция не завершена", + new[] { nameof(wellOperationDtos) }); } + + previous = current; } } diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs index 5c0039cc..79c7d900 100644 --- a/AsbCloudWebApi/Controllers/WellOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellOperationController.cs @@ -237,9 +237,9 @@ namespace AsbCloudWebApi.Controllers wellOperation.IdUser = User.GetUserId(); wellOperation.IdType = idType; - var validationResult = operationRepository.ValidateWithDbAsync(new[] { wellOperation }, cancellationToken); + var validationResult = awaitoperationRepository.ValidateWithDbAsync(new[] { wellOperation }, cancellationToken); if(validationResult.Any()) - return this.ValidationBadRequest(nameof(wellOperation), "The date difference between the operations is more than 3 months"); + return this.ValidationBadRequest(validationResult); var result = await operationRepository.InsertRangeAsync(new[] { wellOperation }, cancellationToken); @@ -294,7 +294,7 @@ namespace AsbCloudWebApi.Controllers var validationResult = Validate(wellOperations, deleteBeforeInsert, cancellationToken); if (validationResult.Any()) - return this.ValidationBadRequest(nameof(wellOperations), "The date difference between the operations is more than 3 months"); + return this.ValidationBadRequest(validationResult); var result = await operationRepository.InsertRangeAsync(wellOperations, cancellationToken); @@ -314,7 +314,7 @@ namespace AsbCloudWebApi.Controllers if (deleteBeforeInsert) return operationRepository.Validate(wellOperations); else - return operationRepository.ValidateWithDbAsync(wellOperations, cancellationToken); + return await operationRepository.ValidateWithDbAsync(wellOperations, cancellationToken); } /// @@ -342,9 +342,9 @@ namespace AsbCloudWebApi.Controllers value.LastUpdateDate = DateTimeOffset.UtcNow; value.IdUser = User.GetUserId(); - var validationResult = operationRepository.ValidateWithDbAsync(new[] { value }, token); + var validationResult = await operationRepository.ValidateWithDbAsync(new[] { value }, token); if (validationResult.Any()) - return this.ValidationBadRequest(nameof(value), "The date difference between the operations is more than 3 months"); + return this.ValidationBadRequest(validationResult); var result = await operationRepository.UpdateAsync(value, token) .ConfigureAwait(false); diff --git a/AsbCloudWebApi/Extentions.cs b/AsbCloudWebApi/Extentions.cs index ba87612f..c064d2de 100644 --- a/AsbCloudWebApi/Extentions.cs +++ b/AsbCloudWebApi/Extentions.cs @@ -3,6 +3,8 @@ using AsbCloudWebApi.Converters; using System; using System.Collections.Generic; using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Linq; using System.Security.Claims; namespace Microsoft.AspNetCore.Mvc @@ -53,6 +55,28 @@ namespace Microsoft.AspNetCore.Mvc return controller.BadRequest(problem); } + /// + /// + /// Returns BadRequest with ValidationProblemDetails as body + /// + /// + /// Используйте этот метод только если валидацию нельзя сделать через + /// атрибуты валидации или IValidatableObject модели. + /// + /// + /// + /// + /// + /// + public static BadRequestObjectResult ValidationBadRequest(this ControllerBase controller, IEnumerable validationResults) + { + var errors = validationResults + .SelectMany(e => e.MemberNames.Select(name=> new { name, e.ErrorMessage })) + .ToDictionary(e => e.name, e => new[] { e.ErrorMessage ?? string.Empty }); + var problem = new ValidationProblemDetails(errors); + return controller.BadRequest(problem); + } + public static MvcOptions UseDateOnlyTimeOnlyStringConverters(this MvcOptions options) { TypeDescriptor.AddAttributes(typeof(DateOnly), new TypeConverterAttribute(typeof(DateOnlyTypeConverter))); From 4bd0a835fce99f3f46071d72597fe91f47f14d40 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 25 Jan 2024 16:52:27 +0500 Subject: [PATCH 7/9] =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudWebApi/Controllers/WellOperationController.cs | 8 ++++---- AsbCloudWebApi/Extentions.cs | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs index 79c7d900..74d4e16f 100644 --- a/AsbCloudWebApi/Controllers/WellOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellOperationController.cs @@ -237,8 +237,8 @@ namespace AsbCloudWebApi.Controllers wellOperation.IdUser = User.GetUserId(); wellOperation.IdType = idType; - var validationResult = awaitoperationRepository.ValidateWithDbAsync(new[] { wellOperation }, cancellationToken); - if(validationResult.Any()) + var validationResult = await operationRepository.ValidateWithDbAsync(new[] { wellOperation }, cancellationToken); + if (validationResult.Any()) return this.ValidationBadRequest(validationResult); var result = await operationRepository.InsertRangeAsync(new[] { wellOperation }, cancellationToken); @@ -292,7 +292,7 @@ namespace AsbCloudWebApi.Controllers } - var validationResult = Validate(wellOperations, deleteBeforeInsert, cancellationToken); + var validationResult = await Validate(wellOperations, deleteBeforeInsert, cancellationToken); if (validationResult.Any()) return this.ValidationBadRequest(validationResult); @@ -309,7 +309,7 @@ namespace AsbCloudWebApi.Controllers /// /// /// - private IEnumerable Validate(IEnumerable wellOperations, bool deleteBeforeInsert, CancellationToken cancellationToken) + private async Task> Validate(IEnumerable wellOperations, bool deleteBeforeInsert, CancellationToken cancellationToken) { if (deleteBeforeInsert) return operationRepository.Validate(wellOperations); diff --git a/AsbCloudWebApi/Extentions.cs b/AsbCloudWebApi/Extentions.cs index c064d2de..5659292c 100644 --- a/AsbCloudWebApi/Extentions.cs +++ b/AsbCloudWebApi/Extentions.cs @@ -65,8 +65,7 @@ namespace Microsoft.AspNetCore.Mvc /// /// /// - /// - /// + /// /// public static BadRequestObjectResult ValidationBadRequest(this ControllerBase controller, IEnumerable validationResults) { From f6e638f8dbaceaa6098fad6de9925c6468bc94af Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 25 Jan 2024 17:13:56 +0500 Subject: [PATCH 8/9] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=8B=D0=B5=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D1=8B:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20wellOperation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Clients/IWellOperationClient.cs | 4 +++ .../WellOperationControllerTest.cs | 30 +++++++++++++++++++ .../Data/Defaults.cs | 2 +- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs index 43497d6c..2db55d36 100644 --- a/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs +++ b/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using Microsoft.AspNetCore.Mvc; using Refit; namespace AsbCloudWebApi.IntegrationTests.Clients; @@ -10,4 +11,7 @@ public interface IWellOperationClient [Post(BaseRoute + "/{idType}/{deleteBeforeInsert}")] Task> InsertRangeAsync(int idWell, int idType, bool deleteBeforeInsert, [Body] IEnumerable dtos); + [Put(BaseRoute + "/{idOperation}")] + Task> UpdateAsync(int idWell, int idOperation, [FromBody] WellOperationDto value, CancellationToken token); + } \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs index 2651243f..809ccf1d 100644 --- a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs +++ b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs @@ -151,4 +151,34 @@ public class WellOperationControllerTest : BaseIntegrationTest //assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } + + /// + /// Успешное обновление операции + /// + /// + [Fact] + public async Task UpdateAsync_returns_success() + { + //act + var dto = dtos.FirstOrDefault()!; + var response = await wellOperationClient.UpdateAsync(idWell, 1, dto, CancellationToken.None); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + /// + /// Неуспешное обновление операции + /// + /// + [Fact] + public async Task UpdateAsync_returns_error() + { + //act + var dto = dtosWithError.LastOrDefault()!; + var response = await wellOperationClient.UpdateAsync(idWell, 1, dto, CancellationToken.None); + + //assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } } \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs b/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs index fc36eb3f..45219449 100644 --- a/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs +++ b/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs @@ -19,7 +19,7 @@ namespace AsbCloudWebApi.IntegrationTests.Data { new() { - Id = 2, + Id = 1, IdWell = 1, IdType = 1, DateStart = DateTimeOffset.UtcNow.AddDays(-1), From 3337112be254023bf570564e8e6c107d2f9f47a0 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Fri, 26 Jan 2024 09:49:00 +0500 Subject: [PATCH 9/9] =?UTF-8?q?=D0=90=D0=B2=D1=82=D0=BE=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D1=8B=20(=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/WellOperationControllerTest.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs index 809ccf1d..3ac32e40 100644 --- a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs +++ b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudDb.Model; using AsbCloudWebApi.IntegrationTests.Clients; using System.Net; using Xunit; @@ -96,14 +97,15 @@ public class WellOperationControllerTest : BaseIntegrationTest } /// - /// Успешное добавление операций (с предварительной очисткой данных) + /// Успешное добавление операций (без предварительной очистки данных) /// /// [Fact] public async Task InsertRange_returns_success() { + dbContext.CleanupDbSet(); //act - var response = await wellOperationClient.InsertRangeAsync(idWell, 1, true, dtos); + var response = await wellOperationClient.InsertRangeAsync(idWell, 1, false, dtos); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -111,14 +113,14 @@ public class WellOperationControllerTest : BaseIntegrationTest /// - /// Неуспешное добавление операций (с предварительной очисткой данных) + /// Неуспешное добавление операций (без предварительной очистки данных) /// /// [Fact] public async Task InsertRange_returns_error() { //act - var response = await wellOperationClient.InsertRangeAsync(idWell, 1, true, dtosWithError); + var response = await wellOperationClient.InsertRangeAsync(idWell, 1, false, dtosWithError); //assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); @@ -132,7 +134,7 @@ public class WellOperationControllerTest : BaseIntegrationTest public async Task InsertRangeWithDeleteBefore_returns_success() { //act - var response = await wellOperationClient.InsertRangeAsync(idWell, 1, false, dtos); + var response = await wellOperationClient.InsertRangeAsync(idWell, 1, true, dtos); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -146,7 +148,7 @@ public class WellOperationControllerTest : BaseIntegrationTest public async Task InsertRangeWithDeleteBefore_returns_error() { //act - var response = await wellOperationClient.InsertRangeAsync(idWell, 1, false, dtosWithError); + var response = await wellOperationClient.InsertRangeAsync(idWell, 1, true, dtosWithError); //assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);