Compare commits

24 Commits

Author SHA1 Message Date
9f51f508ce Merge pull request 'Always use current datetime for validation' (#16) from fix/stale-datetime-validation into main
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #16
2025-10-16 18:23:44 +02:00
62824549fc Always use current datetime for validation
Some checks failed
continuous-integration/drone/push Build was killed
continuous-integration/drone/pr Build is passing
2025-10-16 18:21:14 +02:00
7d7f5750e3 Merge pull request 'Fix bash syntax for creating a variable' (#14) from fix/pipeline into main
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #14
2025-10-16 17:51:33 +02:00
789ba35c60 Fix bash syntax for creating a variable
Some checks failed
continuous-integration/drone/push Build was killed
continuous-integration/drone/pr Build is passing
2025-10-16 17:48:05 +02:00
1226c42f19 Merge pull request 'Echo docker image with tag in pipeline' (#13) from feature/docker-image-echoed-in-pipeline into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #13
2025-10-16 17:41:32 +02:00
5e083aeaf6 Echo docker image with tag in pipeline
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-10-16 17:36:15 +02:00
69bb19e4eb Merge pull request 'Better debug date time error when creating a consumptions' (#11) from fix/bad-request-due-to-date into main
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #11
2025-10-16 17:28:43 +02:00
db791a1183 Add endpoint to query the system's current time
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-10-16 17:23:47 +02:00
ad77c2fe2b Fix logs showing non enumerated enumerable as error messages
All checks were successful
continuous-integration/drone/push Build is passing
2025-10-16 17:15:11 +02:00
87a0241f11 Update packages 2025-10-16 17:14:49 +02:00
5956f27646 Merge pull request 'feature/add-seq-api-key-support' (#8) from feature/add-seq-api-key-support into main
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
Reviewed-on: #8
2025-09-21 11:14:06 +02:00
69901a295c Do not build and push docker image for pull requests
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-09-21 11:07:26 +02:00
527759eb7b Fix fluent assertions version
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2025-09-21 10:56:56 +02:00
d4fff6741c Update packages
Some checks failed
continuous-integration/drone/pr Build is failing
2025-09-21 10:50:33 +02:00
a10070b9c7 Add seq api key support 2025-09-21 10:50:08 +02:00
d10d1a6fdb Docker push and build for production branch as well
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-19 19:01:27 +02:00
97a275478d Update configuration documentation in README
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-07-22 21:13:26 +02:00
731eab3898 Prevent using seq if no seq host is set 2025-07-22 21:13:18 +02:00
f018e62163 Fix Docker build
node:lts seems to be bugged, npm binary does not work right
2025-07-22 21:12:50 +02:00
10e02b5e9b Merge pull request 'Add Seq support' (#6) from feature/traces into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #6
2025-07-22 20:20:24 +02:00
c365af1d42 Add Seq support
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2025-07-22 20:19:57 +02:00
7ddc346e88 Use full type as log category
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-07-21 21:41:16 +02:00
925293d626 Merge pull request 'Add docker build intructions' (#3) from feature/readme into main
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #3
2025-07-21 21:22:18 +02:00
9b024967e6 Add docker build intructions
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2025-07-21 21:22:05 +02:00
22 changed files with 203 additions and 89 deletions

View File

@@ -42,9 +42,11 @@ steps:
- name: docker build and push - name: docker build and push
image: docker:24.0.7 image: docker:24.0.7
commands: commands:
- docker build . -t $docker_registry$docker_repo:$DRONE_BRANCH - dockerImageWithTag="$docker_registry$docker_repo:$DRONE_BRANCH"
- docker build . -t $dockerImageWithTag
- echo $docker_password | docker login --username $docker_username --password-stdin $docker_registry - echo $docker_password | docker login --username $docker_username --password-stdin $docker_registry
- docker push $docker_registry$docker_repo:$DRONE_BRANCH - docker push $dockerImageWithTag
- echo "Built and pushed $dockerImageWithTag"
environment: environment:
docker_username: docker_username:
from_secret: docker_username from_secret: docker_username
@@ -60,6 +62,10 @@ steps:
when: when:
branch: branch:
- main - main
- production
event:
exclude:
- pull_request
depends_on: depends_on:
- compile (.NET) - compile (.NET)
- test - test

View File

@@ -2,18 +2,20 @@
Vegasco (**VE**hicle **GAS** **CO**nsumption) application. Vegasco (**VE**hicle **GAS** **CO**nsumption) application.
Includes the backend (`src/Vegasco.Server.Api`) and the frontend (`src/Vegasco-Web`). Utilizes [Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview). Includes the backend (`src/Vegasco.Server.Api`) and the frontend (`src/Vegasco-Web`). Uses [Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview).
## Getting Started ## Getting Started
### Configuration ### Configuration
| Configuration | Description | Default | Required | | Configuration | Description | Default | Required |
|--------------------------|---------------------------------------------------------------------------------------------------------------|------------------------------------------------------------|----------| |------------------------------------|---------------------------------------------------------------------------------------------------------------|------------------------------------------------------------|----------|
| JWT:MetadataUrl | The oidc meta data url | - | true | | JWT:MetadataUrl | The oidc meta data url | - | true |
| JWT:ValidAudience | The valid audience of the JWT token. | - | true | | JWT:ValidAudience | The valid audience of the JWT token. | - | true |
| JWT:NameClaimType | The claim type of the user's name claim. For keycloak, using `preferred_username` is often the better choice. | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name | false | | JWT:NameClaimType | The claim type of the user's name claim. For keycloak, using `preferred_username` is often the better choice. | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name | false |
| JWT:AllowHttpMetadataUrl | Whether to allow the meta data url to have http as protocol. Always true when `ASPNETCORE_ENVIRONMENT=true` | false | false | | JWT:AllowHttpMetadataUrl | Whether to allow the meta data url to have http as protocol. Always true when `ASPNETCORE_ENVIRONMENT=true` | false | false |
| ConnectionStrings:seq | The seq http endpoint to send the logs and traces to. If not set, logs and traces will not be sent to seq. | - | false |
| ConnectionStrings:vegasco-database | The connection string to the postgres database. | - | true |
The application uses the prefix `Vegasco_` for environment variable names. The prefix is removed when the application reads the environment variables and duplicate entries are overwritten by the environment variables. The application uses the prefix `Vegasco_` for environment variable names. The prefix is removed when the application reads the environment variables and duplicate entries are overwritten by the environment variables.
@@ -67,3 +69,17 @@ creates a Postgres database as a docker container, and starts the Api with the c
Ensure you have an identity provider set up, for example Keycloak, and configured the relevant options described above. Ensure you have an identity provider set up, for example Keycloak, and configured the relevant options described above.
Then, to run the application, ensure you have Docker running, then run either the `http` or `https` launch profile of the `Vegasco.Server.AppHost` project. Then, to run the application, ensure you have Docker running, then run either the `http` or `https` launch profile of the `Vegasco.Server.AppHost` project.
## Deployment
Build server by running in project root:
```shell
docker build . -t docker.nuyken.dev/vegasco/api:main
```
Builder web client by running in `src/Vegasco-Web`:
```shell
docker build -t docker.nuyken.dev/vegasco/web:main --build-arg CONFIGURATION=production .
```

View File

@@ -1,4 +1,4 @@
FROM node:lts AS build FROM node:latest AS build
RUN npm install -g pnpm RUN npm install -g pnpm
ARG CONFIGURATION=development ARG CONFIGURATION=development
WORKDIR /usr/local/app WORKDIR /usr/local/app

View File

@@ -11,6 +11,7 @@ namespace Vegasco.Server.Api.Cars;
public static class CreateCar public static class CreateCar
{ {
public record Request(string Name); public record Request(string Name);
public record Response(Guid Id, string Name); public record Response(Guid Id, string Name);
public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder builder) public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder builder)
@@ -42,18 +43,22 @@ public static class CreateCar
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
ILogger logger = loggerFactory.CreateLogger(nameof(CreateCar)); ILogger logger = loggerFactory.CreateLogger(typeof(CreateCar));
List<ValidationResult> failedValidations = await validators.ValidateAllAsync(request, cancellationToken: cancellationToken); List<ValidationResult> failedValidations =
await validators.ValidateAllAsync(request, cancellationToken: cancellationToken);
if (failedValidations.Count > 0) if (failedValidations.Count > 0)
{ {
string[] errors = failedValidations
.Where(x => !x.IsValid)
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage)
.ToArray();
logger.LogDebug( logger.LogDebug(
"Validation failed for request {@Request} with errors {@Errors}", "Validation failed for request {@Request} with errors {@Errors}",
request, request,
failedValidations errors);
.Where(x => !x.IsValid)
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); 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); logger.LogDebug("User with ID '{UserId}' not found, creating new user", userId);
user = new User user = new User { Id = userId };
{
Id = userId
};
await dbContext.Users.AddAsync(user, cancellationToken); await dbContext.Users.AddAsync(user, cancellationToken);
} }
Car car = new() Car car = new() { Name = request.Name.Trim(), UserId = userId };
{
Name = request.Name.Trim(),
UserId = userId
};
await dbContext.Cars.AddAsync(car, cancellationToken); await dbContext.Cars.AddAsync(car, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken); await dbContext.SaveChangesAsync(cancellationToken);
@@ -95,4 +93,4 @@ public static class CreateCar
Response response = new(car.Id.Value, car.Name); Response response = new(car.Id.Value, car.Name);
return TypedResults.Created($"/v1/cars/{car.Id}", response); return TypedResults.Created($"/v1/cars/{car.Id}", response);
} }
} }

View File

@@ -36,7 +36,7 @@ public static class DeleteCar
if (rows > 1) if (rows > 1)
{ {
ILogger logger = loggerFactory.CreateLogger(nameof(DeleteCar)); ILogger logger = loggerFactory.CreateLogger(typeof(DeleteCar));
logger.LogWarning("Deleted '{DeletedRowCount}' rows for id '{CarId}'", rows, id); logger.LogWarning("Deleted '{DeletedRowCount}' rows for id '{CarId}'", rows, id);
} }

View File

@@ -44,18 +44,21 @@ public static class UpdateCar
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var logger = loggerFactory.CreateLogger(nameof(UpdateCar)); ILogger logger = loggerFactory.CreateLogger(typeof(UpdateCar));
List<ValidationResult> failedValidations = await validators.ValidateAllAsync(request, cancellationToken); List<ValidationResult> failedValidations = await validators.ValidateAllAsync(request, cancellationToken);
if (failedValidations.Count > 0) if (failedValidations.Count > 0)
{ {
string[] errors = failedValidations
.Where(x => !x.IsValid)
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage)
.ToArray();
logger.LogDebug( logger.LogDebug(
"Validation failed for request {@Request} with errors {@Errors}", "Validation failed for request {@Request} with errors {@Errors}",
request, request,
failedValidations errors);
.Where(x => !x.IsValid)
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary()));
} }

View File

@@ -18,6 +18,8 @@ public static class DependencyInjectionExtensions
/// <param name="builder"></param> /// <param name="builder"></param>
public static void AddApiServices(this IHostApplicationBuilder builder) public static void AddApiServices(this IHostApplicationBuilder builder)
{ {
builder.AddBuilderServices();
builder.Services builder.Services
.AddMiscellaneousServices() .AddMiscellaneousServices()
.AddCustomOpenApi() .AddCustomOpenApi()
@@ -27,6 +29,24 @@ public static class DependencyInjectionExtensions
builder.AddDbContext(); builder.AddDbContext();
} }
private static IHostApplicationBuilder AddBuilderServices(this IHostApplicationBuilder builder)
{
string? seqHost = builder.Configuration.GetConnectionString("seq");
if (!string.IsNullOrEmpty(seqHost))
{
builder.AddSeqEndpoint("seq", o =>
{
var apiKey = builder.Configuration.GetValue<string>("seq-api-key");
if (!string.IsNullOrEmpty(apiKey))
{
o.ApiKey = apiKey;
}
});
}
return builder;
}
private static IServiceCollection AddMiscellaneousServices(this IServiceCollection services) private static IServiceCollection AddMiscellaneousServices(this IServiceCollection services)
{ {
services.AddSingleton(() => services.AddSingleton(() =>

View File

@@ -26,13 +26,13 @@ public static class CreateConsumption
{ {
public Validator(TimeProvider timeProvider) public Validator(TimeProvider timeProvider)
{ {
DateTime todayEndOfDay = timeProvider.GetUtcNow() Func<DateTimeOffset> getTodayEndOfDay = () => timeProvider.GetUtcNow()
.Date .Date
.AddDays(1) .AddDays(1)
.AddTicks(-1); .AddTicks(-1);
RuleFor(x => x.DateTime.ToUniversalTime()) RuleFor(x => x.DateTime.ToUniversalTime())
.LessThanOrEqualTo(todayEndOfDay) .LessThanOrEqualTo(_ => getTodayEndOfDay())
.WithName(nameof(Request.DateTime)); .WithName(nameof(Request.DateTime));
RuleFor(x => x.Distance) RuleFor(x => x.Distance)
@@ -53,18 +53,21 @@ public static class CreateConsumption
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
ILogger logger = loggerFactory.CreateLogger(nameof(CreateConsumption)); ILogger logger = loggerFactory.CreateLogger(typeof(CreateConsumption));
List<ValidationResult> failedValidations = await validators.ValidateAllAsync(request, cancellationToken); List<ValidationResult> failedValidations = await validators.ValidateAllAsync(request, cancellationToken);
if (failedValidations.Count > 0) if (failedValidations.Count > 0)
{ {
string[] errors = failedValidations
.Where(x => !x.IsValid)
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage)
.ToArray();
logger.LogDebug( logger.LogDebug(
"Validation failed for request {@Request} with errors {@Errors}", "Validation failed for request {@Request} with errors {@Errors}",
request, request,
failedValidations errors);
.Where(x => !x.IsValid)
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary()));
} }

View File

@@ -36,7 +36,7 @@ public static class DeleteConsumption
if (rows > 1) if (rows > 1)
{ {
ILogger logger = loggerFactory.CreateLogger(nameof(DeleteConsumption)); ILogger logger = loggerFactory.CreateLogger(typeof(DeleteConsumption));
logger.LogWarning("Deleted '{DeletedRowCount}' rows for id '{ConsumptionId}'", rows, id); logger.LogWarning("Deleted '{DeletedRowCount}' rows for id '{ConsumptionId}'", rows, id);
} }

View File

@@ -53,7 +53,7 @@ public static class GetConsumptions
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
ILogger logger = loggerFactory.CreateLogger(nameof(GetConsumptions)); ILogger logger = loggerFactory.CreateLogger(typeof(GetConsumptions));
logger.LogTrace("Received request to get consumptions with parameters: {@Request}", request); logger.LogTrace("Received request to get consumptions with parameters: {@Request}", request);
Activity? activity = Activity.Current; Activity? activity = Activity.Current;

View File

@@ -26,13 +26,13 @@ public static class UpdateConsumption
{ {
public Validator(TimeProvider timeProvider) public Validator(TimeProvider timeProvider)
{ {
DateTime todayEndOfDay = timeProvider.GetUtcNow() Func<DateTimeOffset> getTodayEndOfDay = () => timeProvider.GetUtcNow()
.Date .Date
.AddDays(1) .AddDays(1)
.AddTicks(-1); .AddTicks(-1);
RuleFor(x => x.DateTime.ToUniversalTime()) RuleFor(x => x.DateTime.ToUniversalTime())
.LessThanOrEqualTo(todayEndOfDay) .LessThanOrEqualTo(_ => getTodayEndOfDay())
.WithName(nameof(Request.DateTime)); .WithName(nameof(Request.DateTime));
RuleFor(x => x.Distance) RuleFor(x => x.Distance)
@@ -51,18 +51,21 @@ public static class UpdateConsumption
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
ILogger logger = loggerFactory.CreateLogger(nameof(UpdateConsumption)); ILogger logger = loggerFactory.CreateLogger(typeof(UpdateConsumption));
List<ValidationResult> failedValidations = await validators.ValidateAllAsync(request, cancellationToken); List<ValidationResult> failedValidations = await validators.ValidateAllAsync(request, cancellationToken);
if (failedValidations.Count > 0) if (failedValidations.Count > 0)
{ {
string[] errors = failedValidations
.Where(x => !x.IsValid)
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage)
.ToArray();
logger.LogDebug( logger.LogDebug(
"Validation failed for request {@Request} with errors {@Errors}", "Validation failed for request {@Request} with errors {@Errors}",
request, request,
failedValidations errors);
.Where(x => !x.IsValid)
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary()));
} }
@@ -81,6 +84,7 @@ public static class UpdateConsumption
logger.LogTrace("Updated consumption: {@Consumption}", consumption); 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));
} }
} }

View File

@@ -41,5 +41,6 @@ public static class EndpointExtensions
.RequireAuthorization(Constants.Authorization.RequireAuthenticatedUserPolicy); .RequireAuthorization(Constants.Authorization.RequireAuthenticatedUserPolicy);
GetServerInfo.MapEndpoint(versionedApis); GetServerInfo.MapEndpoint(versionedApis);
GetCurrentTime.MapEndpoint(versionedApis);
} }
} }

View File

@@ -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<Response> Endpoint(
TimeProvider timeProvider)
{
return TypedResults.Ok(new Response(timeProvider.GetUtcNow()));
}
}

View File

@@ -2,7 +2,7 @@
namespace Vegasco.Server.Api.Info; namespace Vegasco.Server.Api.Info;
public class GetServerInfo public static class GetServerInfo
{ {
public record Response( public record Response(
string FullVersion, string FullVersion,

View File

@@ -13,23 +13,24 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Asp.Versioning.Http" Version="8.1.0" /> <PackageReference Include="Asp.Versioning.Http" Version="8.1.0" />
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" /> <PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.3.0" /> <PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.5.1" />
<PackageReference Include="Aspire.Seq" Version="9.5.1" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.0.0" /> <PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.10" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.5" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.10">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageReference Include="OpenTelemetry" Version="1.12.0" /> <PackageReference Include="OpenTelemetry" Version="1.13.1" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" /> <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.13.1" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" /> <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.13.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" /> <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" /> <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
<PackageReference Include="Scalar.AspNetCore" Version="2.4.16" /> <PackageReference Include="Scalar.AspNetCore" Version="2.9.0" />
<PackageReference Include="StronglyTypedId" Version="1.0.0-beta08" PrivateAssets="all" ExcludeAssets="runtime" /> <PackageReference Include="StronglyTypedId" Version="1.0.0-beta08" PrivateAssets="all" ExcludeAssets="runtime" />
<PackageReference Include="StronglyTypedId.Templates" Version="1.0.0-beta08" /> <PackageReference Include="StronglyTypedId.Templates" Version="1.0.0-beta08" />
</ItemGroup> </ItemGroup>
@@ -40,7 +41,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.115" /> <PackageReference Update="Nerdbank.GitVersioning" Version="3.8.118" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -8,7 +8,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Update="Nerdbank.GitVersioning"> <PackageReference Update="Nerdbank.GitVersioning">
<Version>3.7.115</Version> <Version>3.8.118</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>

View File

@@ -14,13 +14,21 @@ if (builder.Environment.IsDevelopment())
.WithPgAdmin(); .WithPgAdmin();
} }
IResourceBuilder<SeqResource> seq = builder.AddSeq("seq")
.WithLifetime(ContainerLifetime.Persistent)
.WithDataVolume()
.WithExternalHttpEndpoints()
.WithImageTag("latest");
IResourceBuilder<PostgresDatabaseResource> postgres = postgresBuilder IResourceBuilder<PostgresDatabaseResource> postgres = postgresBuilder
.AddDatabase(Constants.Database.Name); .AddDatabase(Constants.Database.Name);
IResourceBuilder<ProjectResource> api = builder IResourceBuilder<ProjectResource> api = builder
.AddProject<Projects.Vegasco_Server_Api>(Constants.Projects.Api) .AddProject<Projects.Vegasco_Server_Api>(Constants.Projects.Api)
.WithReference(postgres) .WithReference(postgres)
.WaitFor(postgres); .WaitFor(postgres)
.WithReference(seq)
.WaitFor(seq);
builder builder
.AddNpmApp("Vegasco-Web", "../Vegasco-Web") .AddNpmApp("Vegasco-Web", "../Vegasco-Web")

View File

@@ -12,12 +12,13 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.3.0" /> <PackageReference Include="Aspire.Hosting.AppHost" Version="9.5.1" />
<PackageReference Include="Aspire.Hosting.NodeJs" Version="9.3.1" /> <PackageReference Include="Aspire.Hosting.NodeJs" Version="9.5.1" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.3.0" /> <PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.5.1" />
<PackageReference Update="Nerdbank.GitVersioning"> <PackageReference Update="Nerdbank.GitVersioning">
<Version>3.7.115</Version> <Version>3.8.118</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Aspire.Hosting.Seq" Version="9.5.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -10,15 +10,15 @@
<ItemGroup> <ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" /> <FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.5.0" /> <PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.10.0" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="9.3.0" /> <PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="9.5.1" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" /> <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.13.1" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" /> <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.13.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" /> <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" /> <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" /> <PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
<PackageReference Update="Nerdbank.GitVersioning"> <PackageReference Update="Nerdbank.GitVersioning">
<Version>3.7.115</Version> <Version>3.8.118</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>

View File

@@ -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<GetCurrentTime.Response>();
timeInfo.Should().NotBeNull();
timeInfo.CurrentTime.Should().BeCloseTo(DateTimeOffset.UtcNow, TimeSpan.FromSeconds(10));
}
}

View File

@@ -10,21 +10,21 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.14.0" /> <PackageReference Include="Azure.Identity" Version="1.17.0" />
<PackageReference Include="Bogus" Version="35.6.3" /> <PackageReference Include="Bogus" Version="35.6.4" />
<PackageReference Include="coverlet.collector" Version="6.0.4"> <PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="FluentAssertions" Version="[7.2.0,8.0.0)" /> <PackageReference Include="FluentAssertions" Version="[7.2.0,8.0.0)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.5" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.10" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageReference Include="Respawn" Version="6.2.1" /> <PackageReference Include="Respawn" Version="6.2.1" />
<PackageReference Include="System.Formats.Asn1" Version="9.0.5" /> <PackageReference Include="System.Formats.Asn1" Version="9.0.10" />
<PackageReference Include="Testcontainers.PostgreSql" Version="4.5.0" /> <PackageReference Include="Testcontainers.PostgreSql" Version="4.7.0" />
<PackageReference Include="xunit" Version="2.9.3" /> <PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1"> <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
@@ -40,7 +40,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.115" /> <PackageReference Update="Nerdbank.GitVersioning" Version="3.8.118" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -14,12 +14,12 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="FluentAssertions" Version="8.3.0" /> <PackageReference Include="FluentAssertions" Version="8.7.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.5" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.10" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageReference Include="NSubstitute" Version="5.3.0" /> <PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="xunit" Version="2.9.3" /> <PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1"> <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
@@ -34,7 +34,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.115" /> <PackageReference Update="Nerdbank.GitVersioning" Version="3.8.118" />
</ItemGroup> </ItemGroup>
</Project> </Project>