diff --git a/src/Vegasco.Server.Api/Cars/CreateCar.cs b/src/Vegasco.Server.Api/Cars/CreateCar.cs index c4ea28b..981ac36 100644 --- a/src/Vegasco.Server.Api/Cars/CreateCar.cs +++ b/src/Vegasco.Server.Api/Cars/CreateCar.cs @@ -11,6 +11,7 @@ namespace Vegasco.Server.Api.Cars; public static class CreateCar { public record Request(string Name); + public record Response(Guid Id, string Name); public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder builder) @@ -43,17 +44,21 @@ public static class CreateCar CancellationToken cancellationToken) { ILogger logger = loggerFactory.CreateLogger(typeof(CreateCar)); - - List failedValidations = await validators.ValidateAllAsync(request, cancellationToken: cancellationToken); + + List failedValidations = + await validators.ValidateAllAsync(request, cancellationToken: cancellationToken); if (failedValidations.Count > 0) { + string[] errors = failedValidations + .Where(x => !x.IsValid) + .SelectMany(x => x.Errors) + .Select(x => x.ErrorMessage) + .ToArray(); + logger.LogDebug( "Validation failed for request {@Request} with errors {@Errors}", request, - failedValidations - .Where(x => !x.IsValid) - .SelectMany(x => x.Errors) - .Select(x => x.ErrorMessage)); + errors); return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); } @@ -74,18 +79,11 @@ public static class CreateCar { logger.LogDebug("User with ID '{UserId}' not found, creating new user", userId); - user = new User - { - Id = userId - }; + user = new User { Id = userId }; await dbContext.Users.AddAsync(user, cancellationToken); } - Car car = new() - { - Name = request.Name.Trim(), - UserId = userId - }; + Car car = new() { Name = request.Name.Trim(), UserId = userId }; await dbContext.Cars.AddAsync(car, cancellationToken); await dbContext.SaveChangesAsync(cancellationToken); @@ -95,4 +93,4 @@ public static class CreateCar Response response = new(car.Id.Value, car.Name); return TypedResults.Created($"/v1/cars/{car.Id}", response); } -} +} \ No newline at end of file diff --git a/src/Vegasco.Server.Api/Cars/UpdateCar.cs b/src/Vegasco.Server.Api/Cars/UpdateCar.cs index 7410622..6baf675 100644 --- a/src/Vegasco.Server.Api/Cars/UpdateCar.cs +++ b/src/Vegasco.Server.Api/Cars/UpdateCar.cs @@ -49,13 +49,16 @@ public static class UpdateCar List failedValidations = await validators.ValidateAllAsync(request, cancellationToken); if (failedValidations.Count > 0) { + string[] errors = failedValidations + .Where(x => !x.IsValid) + .SelectMany(x => x.Errors) + .Select(x => x.ErrorMessage) + .ToArray(); + logger.LogDebug( "Validation failed for request {@Request} with errors {@Errors}", request, - failedValidations - .Where(x => !x.IsValid) - .SelectMany(x => x.Errors) - .Select(x => x.ErrorMessage)); + errors); return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); } diff --git a/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs b/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs index bdf4a8c..767cdab 100644 --- a/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs +++ b/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs @@ -58,13 +58,16 @@ public static class CreateConsumption List failedValidations = await validators.ValidateAllAsync(request, cancellationToken); if (failedValidations.Count > 0) { + string[] errors = failedValidations + .Where(x => !x.IsValid) + .SelectMany(x => x.Errors) + .Select(x => x.ErrorMessage) + .ToArray(); + logger.LogDebug( "Validation failed for request {@Request} with errors {@Errors}", request, - failedValidations - .Where(x => !x.IsValid) - .SelectMany(x => x.Errors) - .Select(x => x.ErrorMessage)); + errors); return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); } diff --git a/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs b/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs index e81f245..80ce097 100644 --- a/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs +++ b/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs @@ -52,17 +52,20 @@ public static class UpdateConsumption CancellationToken cancellationToken) { ILogger logger = loggerFactory.CreateLogger(typeof(UpdateConsumption)); - + List failedValidations = await validators.ValidateAllAsync(request, cancellationToken); if (failedValidations.Count > 0) { + string[] errors = failedValidations + .Where(x => !x.IsValid) + .SelectMany(x => x.Errors) + .Select(x => x.ErrorMessage) + .ToArray(); + logger.LogDebug( "Validation failed for request {@Request} with errors {@Errors}", request, - failedValidations - .Where(x => !x.IsValid) - .SelectMany(x => x.Errors) - .Select(x => x.ErrorMessage)); + errors); return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); } @@ -81,6 +84,7 @@ public static class UpdateConsumption logger.LogTrace("Updated consumption: {@Consumption}", consumption); - return TypedResults.Ok(new Response(consumption.Id.Value, consumption.DateTime, consumption.Distance, consumption.Amount, consumption.CarId.Value)); + return TypedResults.Ok(new Response(consumption.Id.Value, consumption.DateTime, consumption.Distance, + consumption.Amount, consumption.CarId.Value)); } } \ No newline at end of file diff --git a/src/Vegasco.Server.Api/Endpoints/EndpointExtensions.cs b/src/Vegasco.Server.Api/Endpoints/EndpointExtensions.cs index 0b5901d..1852cbc 100644 --- a/src/Vegasco.Server.Api/Endpoints/EndpointExtensions.cs +++ b/src/Vegasco.Server.Api/Endpoints/EndpointExtensions.cs @@ -41,5 +41,6 @@ public static class EndpointExtensions .RequireAuthorization(Constants.Authorization.RequireAuthenticatedUserPolicy); GetServerInfo.MapEndpoint(versionedApis); + GetCurrentTime.MapEndpoint(versionedApis); } } diff --git a/src/Vegasco.Server.Api/Info/GetCurrentTime.cs b/src/Vegasco.Server.Api/Info/GetCurrentTime.cs new file mode 100644 index 0000000..601b635 --- /dev/null +++ b/src/Vegasco.Server.Api/Info/GetCurrentTime.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Http.HttpResults; + +namespace Vegasco.Server.Api.Info; + +public static class GetCurrentTime +{ + public record Response(DateTimeOffset CurrentTime); + + public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder builder) + { + return builder + .MapGet("info/time", Endpoint) + .WithTags("Info"); + } + + private static Ok Endpoint( + TimeProvider timeProvider) + { + return TypedResults.Ok(new Response(timeProvider.GetUtcNow())); + } +} \ No newline at end of file diff --git a/src/Vegasco.Server.Api/Info/GetServerInfo.cs b/src/Vegasco.Server.Api/Info/GetServerInfo.cs index e188769..735288b 100644 --- a/src/Vegasco.Server.Api/Info/GetServerInfo.cs +++ b/src/Vegasco.Server.Api/Info/GetServerInfo.cs @@ -2,7 +2,7 @@ namespace Vegasco.Server.Api.Info; -public class GetServerInfo +public static class GetServerInfo { public record Response( string FullVersion, diff --git a/src/Vegasco.Server.Api/Vegasco.Server.Api.csproj b/src/Vegasco.Server.Api/Vegasco.Server.Api.csproj index aa38f0e..e05e788 100644 --- a/src/Vegasco.Server.Api/Vegasco.Server.Api.csproj +++ b/src/Vegasco.Server.Api/Vegasco.Server.Api.csproj @@ -13,24 +13,24 @@ - - + + - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + - + @@ -41,7 +41,7 @@ - + diff --git a/src/Vegasco.Server.AppHost.Shared/Vegasco.Server.AppHost.Shared.csproj b/src/Vegasco.Server.AppHost.Shared/Vegasco.Server.AppHost.Shared.csproj index 5808fe7..53f6868 100644 --- a/src/Vegasco.Server.AppHost.Shared/Vegasco.Server.AppHost.Shared.csproj +++ b/src/Vegasco.Server.AppHost.Shared/Vegasco.Server.AppHost.Shared.csproj @@ -8,7 +8,7 @@ - 3.7.115 + 3.8.118 diff --git a/src/Vegasco.Server.AppHost/Vegasco.Server.AppHost.csproj b/src/Vegasco.Server.AppHost/Vegasco.Server.AppHost.csproj index 12eddb3..5df6bb8 100644 --- a/src/Vegasco.Server.AppHost/Vegasco.Server.AppHost.csproj +++ b/src/Vegasco.Server.AppHost/Vegasco.Server.AppHost.csproj @@ -12,13 +12,13 @@ - - - + + + - 3.7.115 + 3.8.118 - + diff --git a/src/Vegasco.Server.ServiceDefaults/Vegasco.Server.ServiceDefaults.csproj b/src/Vegasco.Server.ServiceDefaults/Vegasco.Server.ServiceDefaults.csproj index 4201046..f0f1cdb 100644 --- a/src/Vegasco.Server.ServiceDefaults/Vegasco.Server.ServiceDefaults.csproj +++ b/src/Vegasco.Server.ServiceDefaults/Vegasco.Server.ServiceDefaults.csproj @@ -10,15 +10,15 @@ - - - - + + + + - 3.7.115 + 3.8.118 diff --git a/tests/Vegasco.Server.Api.Tests.Integration/Info/GetCurrentTimeTests.cs b/tests/Vegasco.Server.Api.Tests.Integration/Info/GetCurrentTimeTests.cs new file mode 100644 index 0000000..b5f2b6b --- /dev/null +++ b/tests/Vegasco.Server.Api.Tests.Integration/Info/GetCurrentTimeTests.cs @@ -0,0 +1,32 @@ +using FluentAssertions; +using FluentAssertions.Extensions; +using System.Net.Http.Json; +using Vegasco.Server.Api.Info; + +namespace Vegasco.Server.Api.Tests.Integration.Info; + +[Collection(SharedTestCollection.Name)] +public sealed class GetCurrentTimeTests +{ + private readonly WebAppFactory _factory; + + public GetCurrentTimeTests(WebAppFactory factory) + { + _factory = factory; + } + + [Fact] + public async Task GetServerInfo_ShouldReturnServerInfo_WhenCalled() + { + // Arrange + + // Act + using HttpResponseMessage response = await _factory.HttpClient.GetAsync("/v1/info/time"); + + // Assert + response.IsSuccessStatusCode.Should().BeTrue(); + GetCurrentTime.Response? timeInfo = await response.Content.ReadFromJsonAsync(); + timeInfo.Should().NotBeNull(); + timeInfo.CurrentTime.Should().BeCloseTo(DateTimeOffset.UtcNow, TimeSpan.FromSeconds(10)); + } +} \ No newline at end of file diff --git a/tests/Vegasco.Server.Api.Tests.Integration/Vegasco.Server.Api.Tests.Integration.csproj b/tests/Vegasco.Server.Api.Tests.Integration/Vegasco.Server.Api.Tests.Integration.csproj index 9500e01..7c951d6 100644 --- a/tests/Vegasco.Server.Api.Tests.Integration/Vegasco.Server.Api.Tests.Integration.csproj +++ b/tests/Vegasco.Server.Api.Tests.Integration/Vegasco.Server.Api.Tests.Integration.csproj @@ -10,21 +10,21 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -40,7 +40,7 @@ - + diff --git a/tests/Vegasco.Server.Api.Tests.Unit/Vegasco.Server.Api.Tests.Unit.csproj b/tests/Vegasco.Server.Api.Tests.Unit/Vegasco.Server.Api.Tests.Unit.csproj index e7413e5..d9013e2 100644 --- a/tests/Vegasco.Server.Api.Tests.Unit/Vegasco.Server.Api.Tests.Unit.csproj +++ b/tests/Vegasco.Server.Api.Tests.Unit/Vegasco.Server.Api.Tests.Unit.csproj @@ -14,12 +14,12 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -34,7 +34,7 @@ - +