2024-08-23 18:02:18 +02:00
|
|
|
|
using FluentValidation;
|
|
|
|
|
|
using FluentValidation.Results;
|
2025-06-12 18:22:37 +02:00
|
|
|
|
using Vegasco.Server.Api.Common;
|
|
|
|
|
|
using Vegasco.Server.Api.Persistence;
|
2024-08-23 18:02:18 +02:00
|
|
|
|
|
2025-06-12 18:22:37 +02:00
|
|
|
|
namespace Vegasco.Server.Api.Consumptions;
|
2024-08-23 18:02:18 +02:00
|
|
|
|
|
|
|
|
|
|
public static class UpdateConsumption
|
|
|
|
|
|
{
|
2025-06-22 11:07:02 +02:00
|
|
|
|
public record Request(DateTimeOffset DateTime, double Distance, double Amount);
|
2024-08-23 18:02:18 +02:00
|
|
|
|
|
2025-06-22 11:07:02 +02:00
|
|
|
|
public record Response(Guid Id, DateTimeOffset DateTime, double Distance, double Amount, Guid CarId);
|
2024-08-23 18:02:18 +02:00
|
|
|
|
|
|
|
|
|
|
public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder builder)
|
|
|
|
|
|
{
|
|
|
|
|
|
return builder
|
|
|
|
|
|
.MapPut("consumptions/{id:guid}", Endpoint)
|
2025-06-16 20:28:37 +02:00
|
|
|
|
.WithTags("Consumptions")
|
2025-06-16 20:34:09 +02:00
|
|
|
|
.WithDescription("Updates a consumption entry by ID")
|
2025-06-16 20:28:37 +02:00
|
|
|
|
.Produces<Response>()
|
|
|
|
|
|
.ProducesValidationProblem()
|
|
|
|
|
|
.Produces(404);
|
2024-08-23 18:02:18 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class Validator : AbstractValidator<Request>
|
|
|
|
|
|
{
|
|
|
|
|
|
public Validator(TimeProvider timeProvider)
|
|
|
|
|
|
{
|
2025-06-22 13:18:22 +02:00
|
|
|
|
DateTime todayEndOfDay = timeProvider.GetUtcNow()
|
|
|
|
|
|
.Date
|
|
|
|
|
|
.AddDays(1)
|
|
|
|
|
|
.AddTicks(-1);
|
|
|
|
|
|
|
2024-08-23 18:02:18 +02:00
|
|
|
|
RuleFor(x => x.DateTime.ToUniversalTime())
|
2025-06-22 13:18:22 +02:00
|
|
|
|
.LessThanOrEqualTo(todayEndOfDay)
|
2024-08-23 18:02:18 +02:00
|
|
|
|
.WithName(nameof(Request.DateTime));
|
|
|
|
|
|
|
|
|
|
|
|
RuleFor(x => x.Distance)
|
|
|
|
|
|
.GreaterThan(0);
|
|
|
|
|
|
|
|
|
|
|
|
RuleFor(x => x.Amount)
|
|
|
|
|
|
.GreaterThan(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static async Task<IResult> Endpoint(
|
|
|
|
|
|
ApplicationDbContext dbContext,
|
|
|
|
|
|
Guid id,
|
|
|
|
|
|
Request request,
|
|
|
|
|
|
IEnumerable<IValidator<Request>> validators,
|
2025-07-21 20:58:45 +02:00
|
|
|
|
ILoggerFactory loggerFactory,
|
2024-08-23 18:02:18 +02:00
|
|
|
|
CancellationToken cancellationToken)
|
|
|
|
|
|
{
|
2025-07-21 20:58:45 +02:00
|
|
|
|
ILogger logger = loggerFactory.CreateLogger(nameof(UpdateConsumption));
|
|
|
|
|
|
|
2024-08-23 18:02:18 +02:00
|
|
|
|
List<ValidationResult> failedValidations = await validators.ValidateAllAsync(request, cancellationToken);
|
|
|
|
|
|
if (failedValidations.Count > 0)
|
|
|
|
|
|
{
|
2025-07-21 20:58:45 +02:00
|
|
|
|
logger.LogDebug(
|
|
|
|
|
|
"Validation failed for request {@Request} with errors {@Errors}",
|
|
|
|
|
|
request,
|
|
|
|
|
|
failedValidations
|
|
|
|
|
|
.Where(x => !x.IsValid)
|
|
|
|
|
|
.SelectMany(x => x.Errors)
|
|
|
|
|
|
.Select(x => x.ErrorMessage));
|
|
|
|
|
|
|
2024-08-23 18:02:18 +02:00
|
|
|
|
return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary()));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Consumption? consumption = await dbContext.Consumptions.FindAsync([new ConsumptionId(id)], cancellationToken);
|
|
|
|
|
|
if (consumption is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return TypedResults.NotFound();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
consumption.DateTime = request.DateTime.ToUniversalTime();
|
|
|
|
|
|
consumption.Distance = request.Distance;
|
|
|
|
|
|
consumption.Amount = request.Amount;
|
|
|
|
|
|
|
|
|
|
|
|
await dbContext.SaveChangesAsync(cancellationToken);
|
|
|
|
|
|
|
2025-07-21 20:58:45 +02:00
|
|
|
|
logger.LogTrace("Updated consumption: {@Consumption}", consumption);
|
|
|
|
|
|
|
2025-06-22 11:07:02 +02:00
|
|
|
|
return TypedResults.Ok(new Response(consumption.Id.Value, consumption.DateTime, consumption.Distance, consumption.Amount, consumption.CarId.Value));
|
2024-08-23 18:02:18 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|