forked from ddrilling/AsbCloudServer
SubsystemOperationTimeRequest implements IValidatableObject;
Add Controller.ValidationBadRequest(..)
This commit is contained in:
parent
ab166487fb
commit
772360cb6e
@ -1,4 +1,4 @@
|
||||
using AsbCloudApp.ValidationAttributes;
|
||||
using AsbCloudApp.Validation;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
|
@ -22,25 +22,5 @@ namespace AsbCloudApp.Exceptions
|
||||
{
|
||||
ParamName = paramName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// преобразование в объект валидации
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public object ToValidationErrorObject()
|
||||
=> MakeValidationError(ParamName, Message);
|
||||
|
||||
/// <summary>
|
||||
/// фабрика объекта валидации
|
||||
/// </summary>
|
||||
/// <param name="paramName"></param>
|
||||
/// <param name="errors"></param>
|
||||
/// <returns></returns>
|
||||
public static object MakeValidationError(string paramName, params string[] errors)
|
||||
=> new
|
||||
{
|
||||
name = paramName,
|
||||
errors,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using AsbCloudApp.ValidationAttributes;
|
||||
using AsbCloudApp.Validation;
|
||||
using System;
|
||||
|
||||
namespace AsbCloudApp.Requests;
|
||||
|
@ -1,23 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudApp.Requests
|
||||
{
|
||||
/// <summary>
|
||||
/// класс с фильтрами для запроса
|
||||
/// </summary>
|
||||
public class SubsystemOperationTimeRequest: RequestBase
|
||||
public class SubsystemOperationTimeRequest: RequestBase, IValidatableObject
|
||||
{
|
||||
private static readonly DateTime validationMinDate = new DateTime(2020,01,01,0,0,0,DateTimeKind.Utc);
|
||||
|
||||
/// <summary>
|
||||
/// идентификатор скважины
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// идентификатор подсистемы
|
||||
/// </summary>
|
||||
public IEnumerable<int>? IdsSubsystems { get; set; }
|
||||
public IEnumerable<int> IdsSubsystems { get; set; } = Enumerable.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно дате
|
||||
@ -58,5 +62,32 @@ namespace AsbCloudApp.Requests
|
||||
/// Режим выборки элементов
|
||||
/// </summary>
|
||||
public int SelectMode { get; set; } = SelectModeOuter;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (GtDate.HasValue && GtDate < validationMinDate)
|
||||
yield return new ValidationResult(
|
||||
$"Должно быть больше {validationMinDate:O})",
|
||||
new[] { nameof(GtDate) });
|
||||
|
||||
if (LtDate.HasValue && GtDate.HasValue)
|
||||
{
|
||||
if (LtDate < GtDate)
|
||||
yield return new ValidationResult(
|
||||
$"{nameof(LtDate)} должно быть больше {nameof(GtDate)}. ({LtDate:O} < {GtDate:O})",
|
||||
new[] { nameof(LtDate), nameof(GtDate) });
|
||||
}
|
||||
|
||||
if (LtDepth.HasValue && GtDepth.HasValue)
|
||||
{
|
||||
if (LtDepth < GtDepth)
|
||||
yield return new ValidationResult(
|
||||
$"{nameof(LtDepth)} должно быть больше {nameof(GtDepth)}. ({LtDepth:O} < {GtDepth:O})",
|
||||
new[] { nameof(LtDepth), nameof(GtDepth) });
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AsbCloudApp.ValidationAttributes
|
||||
namespace AsbCloudApp.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Атрибут валидации даты-времени
|
@ -345,7 +345,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems
|
||||
.Where(o => o.IdTelemetry == well.IdTelemetry)
|
||||
.AsNoTracking();
|
||||
|
||||
if (request.IdsSubsystems?.Any() == true)
|
||||
if (request.IdsSubsystems.Any())
|
||||
query = query.Where(o => request.IdsSubsystems.Contains(o.IdSubsystem));
|
||||
|
||||
// # Dates range condition
|
||||
|
@ -1,4 +1,4 @@
|
||||
using AsbCloudApp.ValidationAttributes;
|
||||
using AsbCloudApp.Validation;
|
||||
using System;
|
||||
using Xunit;
|
||||
|
||||
|
@ -119,10 +119,10 @@ namespace AsbCloudWebApi.Controllers
|
||||
return Forbid();
|
||||
|
||||
if (files.Count > 1)
|
||||
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(files), "only 1 file can be uploaded"));
|
||||
throw new ArgumentInvalidException("only 1 file can be uploaded", nameof(files));
|
||||
|
||||
if (files.Count == 0)
|
||||
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(files), "at list 1 file should be uploaded"));
|
||||
throw new ArgumentInvalidException("at list 1 file should be uploaded", nameof(files));
|
||||
|
||||
var fileName = files[0].FileName;
|
||||
|
||||
|
@ -83,16 +83,12 @@ public class NotificationController : ControllerBase
|
||||
/// <returns></returns>
|
||||
[HttpGet("{idNotification}")]
|
||||
[ProducesResponseType(typeof(NotificationDto), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> GetAsync([Required] int idNotification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var notification = await notificationRepository.GetOrDefaultAsync(idNotification, cancellationToken);
|
||||
|
||||
if (notification is null)
|
||||
{
|
||||
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(idNotification),
|
||||
"Уведомление не найдено"));
|
||||
}
|
||||
var notification = await notificationRepository.GetOrDefaultAsync(idNotification, cancellationToken)
|
||||
?? throw new ArgumentInvalidException("Уведомление не найдено", nameof(idNotification));
|
||||
|
||||
return Ok(notification);
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
|
||||
public async Task<IActionResult> ExportAsync(int? idWell, int? idCluster, CancellationToken token)
|
||||
{
|
||||
if (idCluster is null && idWell is null)
|
||||
return this.MakeBadRequest(nameof(idWell), $"One of {nameof(idWell)} or {nameof(idCluster)} mast be set.");
|
||||
return this.ValidationBadRequest(nameof(idWell), $"One of {nameof(idWell)} or {nameof(idCluster)} mast be set.");
|
||||
|
||||
int? idCompany = User.GetCompanyId();
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.Subsystems;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.Subsystems;
|
||||
@ -50,12 +51,12 @@ namespace AsbCloudWebApi.Controllers.Subsystems
|
||||
/// </summary>
|
||||
[HttpGet("stat")]
|
||||
[ProducesResponseType(typeof(IEnumerable<SubsystemStatDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> GetStatAsync([FromQuery] SubsystemOperationTimeRequest request, CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccesToWellAsync(request.IdWell, token))
|
||||
return Forbid();
|
||||
if (!await IsValidRequest(request, token))
|
||||
return BadRequest("Запрашиваемый диапазон должен заканчиваться за 2 часа до текущего времени(после приведения к UTC).");
|
||||
await CustomValidate(request, token);
|
||||
var subsystemResult = await subsystemOperationTimeService.GetStatAsync(request, token);
|
||||
return Ok(subsystemResult);
|
||||
}
|
||||
@ -125,15 +126,14 @@ namespace AsbCloudWebApi.Controllers.Subsystems
|
||||
/// </summary>
|
||||
[HttpGet("operationTime")]
|
||||
[ProducesResponseType(typeof(IEnumerable<SubsystemOperationTimeDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> GetOperationTimeAsync(
|
||||
[FromQuery] SubsystemOperationTimeRequest request,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccesToWellAsync(request.IdWell, token))
|
||||
return Forbid();
|
||||
if (!await IsValidRequest(request, token))
|
||||
return BadRequest("Запрашиваемый диапазон должен заканчиваться за 2 часа до текущего времени(после приведения к UTC).");
|
||||
await CustomValidate(request, token);
|
||||
|
||||
var result = await subsystemOperationTimeService.GetOperationTimeAsync(request, token);
|
||||
return Ok(result);
|
||||
@ -148,14 +148,14 @@ namespace AsbCloudWebApi.Controllers.Subsystems
|
||||
[HttpDelete]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> DeleteAsync(
|
||||
[FromQuery] SubsystemOperationTimeRequest request,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccesToWellAsync(request.IdWell, token))
|
||||
return Forbid();
|
||||
if (!await IsValidRequest(request, token))
|
||||
return BadRequest("Запрашиваемый диапазон должен заканчиваться за 2 часа до текущего времени(после приведения к UTC).");
|
||||
await CustomValidate(request, token);
|
||||
var result = await subsystemOperationTimeService.DeleteAsync(request, token);
|
||||
return Ok(result);
|
||||
}
|
||||
@ -180,20 +180,24 @@ namespace AsbCloudWebApi.Controllers.Subsystems
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
protected async Task<bool> IsValidRequest(SubsystemOperationTimeRequest request, CancellationToken token)
|
||||
|
||||
/// <summary>
|
||||
/// Валидирует запрос и бросает исключение ArgumentInvalidException
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
private async Task CustomValidate(SubsystemOperationTimeRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
if (well is not null && request.LtDate.HasValue)
|
||||
{
|
||||
var ltDate = (DateTimeOffset)request.LtDate;
|
||||
var utcDateRequest = ltDate.ToRemoteDateTime(well.Timezone.Hours);
|
||||
|
||||
var ltDate = request.LtDate.Value;
|
||||
var utcDateRequest = ltDate.ToUtcDateTimeOffset(well.Timezone.Hours);
|
||||
if (utcDateRequest.AddHours(2) > DateTime.UtcNow)
|
||||
{
|
||||
return false;
|
||||
throw new ArgumentInvalidException("Запрашиваемый диапазон должен заканчиваться за 2 часа до текущего времени", nameof(request.LtDate));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPut("{key}")]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public virtual async Task<ActionResult<int>> UpsertAsync(string key, [FromBody] System.Text.Json.JsonDocument value, CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
@ -63,7 +64,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
|
||||
var result = await service.UpsertAsync((int)userId, key, value, token).ConfigureAwait(false);
|
||||
if (result < 0)
|
||||
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(key), "not found"));
|
||||
throw new ArgumentInvalidException("not found", nameof(key));
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
@ -74,6 +75,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{key}")]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public virtual async Task<ActionResult<int>> DeleteAsync(string key, CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
@ -82,7 +84,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
|
||||
var result = await service.DeleteAsync((int)userId, key, token).ConfigureAwait(false);
|
||||
if (result < 0)
|
||||
return BadRequest(ArgumentInvalidException.MakeValidationError(nameof(key), "not found"));
|
||||
throw new ArgumentInvalidException("not found", nameof(key));
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using AsbCloudApp.Data.User;
|
||||
using AsbCloudWebApi.Converters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Security.Claims;
|
||||
|
||||
@ -30,13 +31,26 @@ namespace Microsoft.AspNetCore.Mvc
|
||||
: null;
|
||||
}
|
||||
|
||||
public static IActionResult MakeBadRequest(this ControllerBase controller, string paramName, params string[] errors)
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Returns BadRequest with ValidationProblemDetails as body
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Используйте этот метод только если валидацию нельзя сделать через
|
||||
/// атрибуты валидации или IValidatableObject модели.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="controller"></param>
|
||||
/// <param name="paramName"></param>
|
||||
/// <param name="error"></param>
|
||||
/// <returns></returns>
|
||||
public static BadRequestObjectResult ValidationBadRequest(this ControllerBase controller, string paramName, string error)
|
||||
{
|
||||
return controller.BadRequest(new
|
||||
{
|
||||
name = paramName,
|
||||
errors,
|
||||
});
|
||||
var errors = new Dictionary<string, string[]> {
|
||||
{ paramName, new[]{ error } }
|
||||
};
|
||||
var problem = new ValidationProblemDetails(errors);
|
||||
return controller.BadRequest(problem);
|
||||
}
|
||||
|
||||
public static MvcOptions UseDateOnlyTimeOnlyStringConverters(this MvcOptions options)
|
||||
|
@ -1,8 +1,9 @@
|
||||
// Ignore Spelling: Middlewares
|
||||
|
||||
using AsbCloudApp.Exceptions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.Middlewares
|
||||
@ -55,8 +56,11 @@ namespace AsbCloudWebApi.Middlewares
|
||||
|
||||
private static string MakeJsonBody(ArgumentInvalidException ex)
|
||||
{
|
||||
object error = ex.ToValidationErrorObject();
|
||||
var buffer = System.Text.Json.JsonSerializer.Serialize(error);
|
||||
var errors = new Dictionary<string, string[]> {
|
||||
{ ex.ParamName, new[]{ ex.Message } }
|
||||
};
|
||||
var problem = new ValidationProblemDetails(errors);
|
||||
var buffer = System.Text.Json.JsonSerializer.Serialize(problem);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user