forked from ddrilling/AsbCloudServer
ProcessMapPlanDrilling.http - fix encoding.
Handle foreignKeys exceptions as validation exceptions. Add integr.tests for bad request cases.
This commit is contained in:
parent
8a38777db3
commit
54ef71411a
@ -5,8 +5,10 @@ using AsbCloudApp.Requests;
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudDb.Model.ProcessMapPlan;
|
using AsbCloudDb.Model.ProcessMapPlan;
|
||||||
|
using AsbCloudDb.Model.WellSections;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Npgsql;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -47,8 +49,8 @@ public class ProcessMapPlanBaseRepository<TDto, TEntity> : IProcessMapPlanBaseRe
|
|||||||
entity.Obsolete = null;
|
entity.Obsolete = null;
|
||||||
dbSet.Add(entity);
|
dbSet.Add(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
result += await context.SaveChangesAsync(token);
|
result += await SaveChangesWithExceptionHandling(token);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -60,28 +62,21 @@ public class ProcessMapPlanBaseRepository<TDto, TEntity> : IProcessMapPlanBaseRe
|
|||||||
|
|
||||||
using var transaction = context.Database.BeginTransaction();
|
using var transaction = context.Database.BeginTransaction();
|
||||||
var result = 0;
|
var result = 0;
|
||||||
try
|
|
||||||
|
var dbSet = context.Set<TEntity>();
|
||||||
|
var entitiesToMarkDeleted = dbSet
|
||||||
|
.Where(e => e.IdWell == idWell)
|
||||||
|
.Where(e => e.Obsolete == null);
|
||||||
|
var obsolete = DateTimeOffset.UtcNow;
|
||||||
|
foreach (var entity in entitiesToMarkDeleted)
|
||||||
{
|
{
|
||||||
var dbSet = context.Set<TEntity>();
|
entity.IdState = ChangeLogAbstract.IdClearedOnImport;
|
||||||
var entitiesToMarkDeleted = dbSet
|
entity.Obsolete = obsolete;
|
||||||
.Where(e => e.IdWell == idWell)
|
entity.IdEditor = idUser;
|
||||||
.Where(e => e.Obsolete == null);
|
|
||||||
var obsolete = DateTimeOffset.UtcNow;
|
|
||||||
foreach (var entity in entitiesToMarkDeleted)
|
|
||||||
{
|
|
||||||
entity.IdState = ChangeLogAbstract.IdClearedOnImport;
|
|
||||||
entity.Obsolete = obsolete;
|
|
||||||
entity.IdEditor = idUser;
|
|
||||||
}
|
|
||||||
result += await context.SaveChangesAsync(token);
|
|
||||||
result += await InsertRange(idUser, dtos, token);
|
|
||||||
await transaction.CommitAsync(token);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
await transaction.RollbackAsync(CancellationToken.None);
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
|
result += await SaveChangesWithExceptionHandling(token);
|
||||||
|
result += await InsertRange(idUser, dtos, token);
|
||||||
|
await transaction.CommitAsync(token);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -99,7 +94,7 @@ public class ProcessMapPlanBaseRepository<TDto, TEntity> : IProcessMapPlanBaseRe
|
|||||||
entity.Obsolete = obsolete;
|
entity.Obsolete = obsolete;
|
||||||
entity.IdEditor = idUser;
|
entity.IdEditor = idUser;
|
||||||
}
|
}
|
||||||
var result = await context.SaveChangesAsync(token);
|
var result = await SaveChangesWithExceptionHandling(token);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,48 +196,39 @@ public class ProcessMapPlanBaseRepository<TDto, TEntity> : IProcessMapPlanBaseRe
|
|||||||
|
|
||||||
using var transaction = context.Database.BeginTransaction();
|
using var transaction = context.Database.BeginTransaction();
|
||||||
var result = 0;
|
var result = 0;
|
||||||
try
|
|
||||||
|
var ids = dtos.Select(d => d.Id);
|
||||||
|
var dbSet = context.Set<TEntity>();
|
||||||
|
|
||||||
|
var entitiesToDelete = dbSet
|
||||||
|
.Where(e => ids.Contains(e.Id));
|
||||||
|
|
||||||
|
var updateTime = DateTimeOffset.UtcNow;
|
||||||
|
foreach (var entity in entitiesToDelete)
|
||||||
{
|
{
|
||||||
var ids = dtos.Select(d => d.Id);
|
if(entity.Obsolete is not null)
|
||||||
var dbSet = context.Set<TEntity>();
|
throw new ArgumentInvalidException(nameof(dtos), "Недопустимо редактировать устаревшие записи");
|
||||||
|
entity.IdState = ChangeLogAbstract.IdStateReplaced;
|
||||||
var entitiesToDelete = dbSet
|
entity.Obsolete = updateTime;
|
||||||
.Where(e => ids.Contains(e.Id));
|
entity.IdEditor = idUser;
|
||||||
|
|
||||||
var updateTime = DateTimeOffset.UtcNow;
|
|
||||||
foreach (var entity in entitiesToDelete)
|
|
||||||
{
|
|
||||||
if(entity.Obsolete is not null)
|
|
||||||
throw new ArgumentInvalidException(nameof(dtos), "Недопустимо редактировать устаревшие записи");
|
|
||||||
entity.IdState = ChangeLogAbstract.IdStateReplaced;
|
|
||||||
entity.Obsolete = updateTime;
|
|
||||||
entity.IdEditor = idUser;
|
|
||||||
}
|
|
||||||
result += await context.SaveChangesAsync(token);
|
|
||||||
|
|
||||||
var entitiesNew = dtos.Select(Convert);
|
|
||||||
foreach (var entity in entitiesNew)
|
|
||||||
{
|
|
||||||
entity.IdPrevious = entity.Id;
|
|
||||||
entity.Id = default;
|
|
||||||
entity.Creation = updateTime;
|
|
||||||
entity.IdAuthor = idUser;
|
|
||||||
entity.Obsolete = null;
|
|
||||||
entity.IdEditor = null;
|
|
||||||
entity.IdState = ChangeLogAbstract.IdStateActual;
|
|
||||||
dbSet.Add(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
result += await context.SaveChangesAsync(token);
|
|
||||||
|
|
||||||
await transaction.CommitAsync(token);
|
|
||||||
}
|
}
|
||||||
catch
|
result += await context.SaveChangesAsync(token);
|
||||||
|
|
||||||
|
var entitiesNew = dtos.Select(Convert);
|
||||||
|
foreach (var entity in entitiesNew)
|
||||||
{
|
{
|
||||||
await transaction.RollbackAsync(CancellationToken.None);
|
entity.IdPrevious = entity.Id;
|
||||||
throw;
|
entity.Id = default;
|
||||||
|
entity.Creation = updateTime;
|
||||||
|
entity.IdAuthor = idUser;
|
||||||
|
entity.Obsolete = null;
|
||||||
|
entity.IdEditor = null;
|
||||||
|
entity.IdState = ChangeLogAbstract.IdStateActual;
|
||||||
|
dbSet.Add(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result += await SaveChangesWithExceptionHandling(token);
|
||||||
|
await transaction.CommitAsync(token);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,4 +253,25 @@ public class ProcessMapPlanBaseRepository<TDto, TEntity> : IProcessMapPlanBaseRe
|
|||||||
|
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<int> SaveChangesWithExceptionHandling(CancellationToken token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await context.SaveChangesAsync(token);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (DbUpdateException ex)
|
||||||
|
{
|
||||||
|
if (ex.InnerException is PostgresException pgException)
|
||||||
|
TryConvertPostgresExceptionToValidateException(pgException);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TryConvertPostgresExceptionToValidateException(PostgresException pgException)
|
||||||
|
{
|
||||||
|
if (pgException.SqlState == PostgresErrorCodes.ForeignKeyViolation)
|
||||||
|
throw new ArgumentInvalidException("dtos", pgException.Message + "\r\n" + pgException.Detail);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,57 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest
|
|||||||
MatchHelper.Match(expected, actual, excludeProps);
|
MatchHelper.Match(expected, actual, excludeProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InsertRange_returns_BadRequest_for_IdWellSectionType()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dbset = dbContext.Set<ProcessMapPlanDrilling>();
|
||||||
|
dbset.RemoveRange(dbset);
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
var badDto = dto.Adapt<ProcessMapPlanDrillingDto>();
|
||||||
|
badDto.IdWellSectionType = int.MaxValue;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await client.InsertRange(dto.IdWell, new[] { badDto });
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InsertRange_returns_BadRequest_for_IdMode()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dbset = dbContext.Set<ProcessMapPlanDrilling>();
|
||||||
|
dbset.RemoveRange(dbset);
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
var badDto = dto.Adapt<ProcessMapPlanDrillingDto>();
|
||||||
|
badDto.IdMode = int.MaxValue;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await client.InsertRange(dto.IdWell, new[] { badDto });
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InsertRange_returns_BadRequest_for_IdWell()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dbset = dbContext.Set<ProcessMapPlanDrilling>();
|
||||||
|
dbset.RemoveRange(dbset);
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
var badDto = dto.Adapt<ProcessMapPlanDrillingDto>();
|
||||||
|
badDto.IdWell = int.MaxValue;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await client.InsertRange(dto.IdWell, new[] { badDto });
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ClearAndInsertRange_returns_success()
|
public async Task ClearAndInsertRange_returns_success()
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
@id = 1
|
@id = 1
|
||||||
@idWell = 1
|
@idWell = 1
|
||||||
|
|
||||||
### получение данных drill test с панели и сохранение их в ЕЦП
|
### получение данных drill test с панели и сохранение их в ЕЦП
|
||||||
POST {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling
|
POST {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling
|
||||||
Content-Type: {{contentType}}
|
Content-Type: {{contentType}}
|
||||||
accept: */*
|
accept: */*
|
||||||
@ -54,12 +54,12 @@ Authorization: {{auth}}
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
### Получение всех
|
### Получение всех
|
||||||
GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling
|
GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling
|
||||||
accept: */*
|
accept: */*
|
||||||
Authorization: {{auth}}
|
Authorization: {{auth}}
|
||||||
|
|
||||||
### замена старых записей новыми
|
### замена старых записей новыми
|
||||||
POST {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling/replace
|
POST {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling/replace
|
||||||
Content-Type: {{contentType}}
|
Content-Type: {{contentType}}
|
||||||
accept: */*
|
accept: */*
|
||||||
@ -75,7 +75,7 @@ Authorization: {{auth}}
|
|||||||
"idState": 0,
|
"idState": 0,
|
||||||
"idPrevious": 0,
|
"idPrevious": 0,
|
||||||
"idWell": 1,
|
"idWell": 1,
|
||||||
"idWellSectionType": 1,
|
"idWellSectionType": 1500,
|
||||||
"depthStart": 0,
|
"depthStart": 0,
|
||||||
"depthEnd": 10,
|
"depthEnd": 10,
|
||||||
"idMode": 2,
|
"idMode": 2,
|
||||||
@ -106,22 +106,22 @@ Authorization: {{auth}}
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
### Получение только актуальных
|
### Получение только актуальных
|
||||||
GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling?Moment=3000-01-01
|
GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling?Moment=3000-01-01
|
||||||
accept: */*
|
accept: */*
|
||||||
Authorization: {{auth}}
|
Authorization: {{auth}}
|
||||||
|
|
||||||
### Получение
|
### Получение
|
||||||
GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling/dates
|
GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling/dates
|
||||||
accept: */*
|
accept: */*
|
||||||
Authorization: {{auth}}
|
Authorization: {{auth}}
|
||||||
|
|
||||||
### Получение изменений за дату
|
### Получение изменений за дату
|
||||||
GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling/changeLog?date=2024-01-19
|
GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling/changeLog?date=2024-01-19
|
||||||
accept: */*
|
accept: */*
|
||||||
Authorization: {{auth}}
|
Authorization: {{auth}}
|
||||||
|
|
||||||
### удаление
|
### удаление
|
||||||
DELETE {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling
|
DELETE {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling
|
||||||
Content-Type: {{contentType}}
|
Content-Type: {{contentType}}
|
||||||
accept: */*
|
accept: */*
|
Loading…
Reference in New Issue
Block a user