Skip to content

Commit

Permalink
Merge pull request #11 from kamil-oberaj/KO/reservations
Browse files Browse the repository at this point in the history
[feat]: Reservations
  • Loading branch information
kamil-oberaj authored May 23, 2024
2 parents d61a6ba + 9ee55f6 commit 90c8527
Show file tree
Hide file tree
Showing 148 changed files with 2,975 additions and 660 deletions.
20 changes: 10 additions & 10 deletions .github/workflows/build_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
on:
push:
branches:
- master
- master
pull_request:
branches:
- '**'
- '**'

jobs:
build:
name: Restore, Build and Test
Expand All @@ -18,21 +18,21 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

- name: Restore Packages
run: dotnet restore

- name: Build
run: dotnet build --configuration Release

- name: Test
run: dotnet test --configuration Release --no-build --verbosity normal --logger trx --collect:"XPlat Code Coverage"
run: dotnet test --configuration Release --no-build --verbosity normal --logger trx --collect:"XPlat Code Coverage" --settings coverlet.runsettings

- name: Combine Coverage Reports
uses: danielpalme/[email protected]
with:
Expand All @@ -43,7 +43,7 @@ jobs:
title: "Code Coverage"
tag: "${{ github.run_number }}_${{ github.run_id }}"
toolpath: "reportgeneratortool"

- name: Upload Combined Coverage XML
uses: actions/upload-artifact@v4
with:
Expand Down
7 changes: 7 additions & 0 deletions StudioManager.API.Contracts/Common/NamedBaseDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace StudioManager.API.Contracts.Common;

public class NamedBaseDto
{
public Guid Id { get; init; }
public string Name { get; init; } = null!;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace StudioManager.API.Contracts.EquipmentTypes;

public sealed record EquipmentTypeReadDto(Guid Id, string Name);
public sealed record EquipmentTypeReadDto(Guid Id, string Name);
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace StudioManager.API.Contracts.EquipmentTypes;

public sealed record EquipmentTypeWriteDto(string Name);
public sealed record EquipmentTypeWriteDto(string Name);
8 changes: 7 additions & 1 deletion StudioManager.API.Contracts/Equipments/EquipmentReadDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@

namespace StudioManager.API.Contracts.Equipments;

public sealed record EquipmentReadDto(Guid Id, string Name, int Quantity, int InitialQuantity, string ImageUrl, EquipmentTypeReadDto EquipmentType);
public sealed record EquipmentReadDto(
Guid Id,
string Name,
int Quantity,
int InitialQuantity,
string ImageUrl,
EquipmentTypeReadDto EquipmentType);
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace StudioManager.API.Contracts.Equipments;

public sealed record EquipmentWriteDto(string Name, Guid EquipmentTypeId, int Quantity/*, byte[] Image*/);
public sealed record EquipmentWriteDto(string Name, Guid EquipmentTypeId, int Quantity /*, string ImageUrl*/);
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ public sealed class PaginationDetailsDto
public int Limit { get; set; }
public int Page { get; set; }
public int Total { get; set; }
}
}
27 changes: 20 additions & 7 deletions StudioManager.API.Contracts/Pagination/PaginationDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,30 @@ namespace StudioManager.API.Contracts.Pagination;

public sealed class PaginationDto
{
[Range(0, int.MaxValue)] public int Limit { get; private init; } = 25;
public const int DefaultLimit = 50;
public const int DefaultPage = 1;

[Range(0, int.MaxValue)] public int Page { get; private init; } = 1;
private int? _limit;
private int? _page;

public int GetOffset()
[Range(0, int.MaxValue)]
public int? Limit
{
get => _limit ?? DefaultLimit;
set => _limit = value;
}

[Range(0, int.MaxValue)]
public int? Page
{
return Limit * (Page - 1);
get => _page ?? DefaultPage;
set => _page = value;
}

public static PaginationDto Default()
public int GetOffset()
{
return new PaginationDto { Limit = 25, Page = 1 };
if (!Page.HasValue) return 0;

return Limit!.Value * (Page!.Value - 1);
}
}
}
2 changes: 1 addition & 1 deletion StudioManager.API.Contracts/Pagination/PagingResultDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ public sealed class PagingResultDto<TData>
{
public List<TData> Data { get; set; } = default!;
public PaginationDetailsDto Pagination { get; set; } = default!;
}
}
10 changes: 10 additions & 0 deletions StudioManager.API.Contracts/Reservations/ReservationReadDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using StudioManager.API.Contracts.Common;

namespace StudioManager.API.Contracts.Reservations;

public sealed record ReservationReadDto(
Guid Id,
DateOnly StartDate,
DateOnly EndDate,
int Quantity,
NamedBaseDto Equipment);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace StudioManager.API.Contracts.Reservations;

public sealed record ReservationWriteDto(DateOnly StartDate, DateOnly EndDate, int Quantity, Guid EquipmentId);
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,4 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore;
using StudioManager.Application.DbContextExtensions;
using StudioManager.Domain.Filters;
using StudioManager.Infrastructure;
using StudioManager.Infrastructure.Common;
using StudioManager.Notifications.Equipment;

namespace StudioManager.API.BackgroundServices;

[ExcludeFromCodeCoverage]
//TODO: Create read lock for this service
public sealed class FinishedReservationsBackgroundService(
IDbContextFactory<StudioManagerDbContext> dbContextFactory)
: BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromDays(1), stoppingToken);

await using var dbContext = await dbContextFactory.CreateDbContextAsync(stoppingToken);
{
await ReturnReservationsAsync(dbContext, stoppingToken);
}
}
}

private static async Task ReturnReservationsAsync(DbContextBase dbContext, CancellationToken cancellationToken)
{
var filter = new ReservationFilter { EndDate = DateOnly.FromDateTime(DateTime.Today) };

var reservations = await dbContext.GetReservationsAsync(filter, cancellationToken);

if (reservations.Count == 0) return;

foreach (var reservation in reservations)
reservation.AddDomainEvent(new EquipmentReturnedEvent(reservation.EquipmentId, 0));

await dbContext.SaveChangesAsync(cancellationToken);
}
}
36 changes: 12 additions & 24 deletions StudioManager.API/Base/CoreController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace StudioManager.API.Base;
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[Produces(contentType: "application/json", "application/problem+json")]
[Produces("application/json", "application/problem+json")]
[ExcludeFromCodeCoverage]
//[Authorize(Policy = "AuthorizedUser")]
public abstract class CoreController(ISender sender) : ControllerBase
Expand All @@ -22,7 +22,7 @@ internal async Task<IResult> SendAsync(IRequest<CommandResult> request)

return CreateResult(result);
}

internal async Task<IResult> SendAsync<T>(IRequest<QueryResult<T>> request)
{
var result = await sender.Send(request);
Expand All @@ -40,50 +40,38 @@ private static IResult CreateResult<T>(IRequestResult<T> requestResult)
_ => FromUnexpectedErrorResult(requestResult)
};
}

private static IResult FromSucceededResult<T>(IRequestResult<T> requestResult)
{
if (!requestResult.Succeeded)
{
throw new InvalidOperationException(EX.SUCCESS_FROM_ERROR);
}

if (!requestResult.Succeeded) throw new InvalidOperationException(EX.SUCCESS_FROM_ERROR);

return Results.Ok(requestResult.Data);
}

private static IResult FromNotFoundResult<T>(IRequestResult<T> requestResult)
{
if (requestResult.Succeeded)
{
throw new InvalidOperationException(EX.ERROR_FROM_SUCCESS);
}
if (requestResult.Succeeded) throw new InvalidOperationException(EX.ERROR_FROM_SUCCESS);

return Results.Problem(
statusCode: StatusCodes.Status404NotFound,
detail: requestResult.Error);
}

private static IResult FromConflictResult<T>(IRequestResult<T> requestResult)
{
if (requestResult.Succeeded)
{
throw new InvalidOperationException(EX.ERROR_FROM_SUCCESS);
}
if (requestResult.Succeeded) throw new InvalidOperationException(EX.ERROR_FROM_SUCCESS);

return Results.Problem(
statusCode: StatusCodes.Status409Conflict,
detail: requestResult.Error);
}

private static IResult FromUnexpectedErrorResult<T>(IRequestResult<T> requestResult)
{
if (requestResult.Succeeded)
{
throw new InvalidOperationException(EX.ERROR_FROM_SUCCESS);
}
if (requestResult.Succeeded) throw new InvalidOperationException(EX.ERROR_FROM_SUCCESS);

return Results.Problem(
statusCode: StatusCodes.Status500InternalServerError,
detail: requestResult.Error);
}
}
}
5 changes: 3 additions & 2 deletions StudioManager.API/Behaviours/RequestLoggingBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public class RequestLoggingBehavior<TRequest, TResponse>(
: IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
var stopWatch = new Stopwatch();
stopWatch.Start();
Expand All @@ -39,4 +40,4 @@ public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TRe
typeof(TRequest).Name, elapsed, DateTime.UtcNow);
}
}
}
}
17 changes: 6 additions & 11 deletions StudioManager.API/Behaviours/ValidationBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@ public sealed class ValidationBehavior<TRequest, TResponse>(
: IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
if (!validators.Any())
{
return await next();
}

if (!validators.Any()) return await next();

var context = new ValidationContext<TRequest>(request);

var validationFailures = await Task.WhenAll(
Expand All @@ -31,11 +29,8 @@ public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TRe
validationFailure.ErrorMessage))
.ToList();

if (errors.Count != 0)
{
throw new ValidationException(errors);
}
if (errors.Count != 0) throw new ValidationException(errors);

return await next();
}
}
}
Loading

0 comments on commit 90c8527

Please sign in to comment.