Skip to content

Commit

Permalink
Merge pull request #16 from GuilhermeBley/main
Browse files Browse the repository at this point in the history
New endpoints configurations
  • Loading branch information
GuilhermeBley authored Nov 14, 2024
2 parents 38514f5 + dcfc599 commit f469a80
Show file tree
Hide file tree
Showing 36 changed files with 982 additions and 177 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ await mediator.Send(new Application.Commands.Gym.GetGymMembers.GetGymMembersRequ

return Results.Ok(result);

}).RequireAuthorization(cfg =>
{
cfg.RequireRole(Domain.Security.UserClaim.ManageGymGroup.Value);
});
}).RequireAuthorization();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,6 @@ public static void MapEndpoints(IEndpointRouteBuilder builder)
return Results.Ok(result);
}).RequireAuthorization();

builder.MapPatch("Training/{sectionId}/update-current-training-days", async (
HttpContext context,
IMediator mediator,
Guid sectionId,
[FromBody] Application.Commands.Training.UpdateCurrentDaysCountFromSection.UpdateCurrentDaysCountFromSectionRequest request) =>
{
if (sectionId != request.SectionId)
return Results.Unauthorized();

var result =
await mediator.Send(request);

return Results.Ok(result);
}).RequireAuthorization();

builder.MapGet("Training/exercises/gym/{gymId}", async (
HttpContext context,
Guid gymId,
Expand All @@ -77,5 +62,29 @@ await mediator.Send(

return Results.Ok(result);
}).RequireAuthorization();

builder.MapPost("Training/section/{sectionId}/period", async (
HttpContext context,
Guid sectionId,
[FromServices] IMediator mediator) =>
{
var result =
await mediator.Send(
new Application.Commands.Training.StartTrainingPeriod.StartTrainingPeriodRequest(sectionId));

return Results.Created($"Training/section/{sectionId}/period", result);
}).RequireAuthorization();

builder.MapPost("Training/section/{sectionId}/period/finish", async (
HttpContext context,
Guid sectionId,
[FromServices] IMediator mediator) =>
{
var result =
await mediator.Send(
new Application.Commands.Training.FinishTrainingPeriod.FinishTrainingPeriodRequest(sectionId));

return Results.Created($"Training/section/{sectionId}/period", result);
}).RequireAuthorization();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ var userAlreadyContainsAnActiveTrainingInThisGym
var studentSheet = UserTrainingSheet.CreateNow(
request.StudentId,
request.GymId,
request.Sets.Select(section =>
request.Sections.Select(section =>
{
var setEntity = TrainingSection.CreateNew(
Guid.NewGuid(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
public record CreateTrainingToStudentRequest(
Guid GymId,
Guid StudentId,
IEnumerable<CreateTrainingToStudentSection> Sets)
IEnumerable<CreateTrainingToStudentSection> Sections)
: IRequest<CreateTrainingToStudentResponse>;

public record CreateTrainingToStudentSection(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@

using Bl.Gym.TrainingApi.Application.Providers;
using Bl.Gym.TrainingApi.Application.Repositories;
using Bl.Gym.TrainingApi.Application.Services;

namespace Bl.Gym.TrainingApi.Application.Commands.Training.FinishTrainingPeriod;

public class FinishTrainingPeriodHandler
: IRequestHandler<FinishTrainingPeriodRequest, FinishTrainingPeriodResponse>
{
private readonly IIdentityProvider _identityProvider;
private readonly TrainingContext _context;
private readonly GymRoleCheckerService _gymChecker;
private readonly ILogger<FinishTrainingPeriodHandler> _logger;

public FinishTrainingPeriodHandler(
IIdentityProvider identityProvider,
TrainingContext context,
GymRoleCheckerService gymChecker,
ILogger<FinishTrainingPeriodHandler> logger)
{
_identityProvider = identityProvider;
_context = context;
_gymChecker = gymChecker;
_logger = logger;
}

public async Task<FinishTrainingPeriodResponse> Handle(
FinishTrainingPeriodRequest request,
CancellationToken cancellationToken)
{
var user = await _identityProvider.GetCurrentAsync(cancellationToken);

user.ThrowIfDoesntContainRole(Domain.Security.UserClaim.SeeTraining);

var periodToUpdate = await _context
.TrainingsPeriod
.Where(e => e.Id == request.PeriodId)
.FirstOrDefaultAsync(cancellationToken)
?? throw CoreException.CreateByCode(CoreExceptionCode.NotFound);

var periodEntity = periodToUpdate.MapToEntity();

periodEntity.Update(periodEntity.StartedAt ?? DateTime.UtcNow, DateTime.UtcNow);

await _gymChecker.ThrowIfUserIsntInTheSectionAsync(user.RequiredUserId(), periodToUpdate.SectionId, cancellationToken);

var sheetFound = await
(from sheet in _context.UserTrainingSheets.AsNoTracking()
join section in _context.TrainingSections.AsNoTracking()
on sheet.Id equals section.UserTrainingSheetId
select sheet).FirstOrDefaultAsync(cancellationToken)
?? throw CoreException.CreateByCode(CoreExceptionCode.NotFound);

if (sheetFound.Status != Domain.Enum.UserTrainingStatus.InProgress)
{
_logger.LogInformation("Sheet {0} was not started.", sheetFound.Id);
throw CoreException.CreateByCode(CoreExceptionCode.ThisUserSheetIsntStarted);
}

var sectionFound = await _context
.TrainingSections
.AsNoTracking()
.Where(e => e.Id == periodToUpdate.SectionId)
.FirstOrDefaultAsync(cancellationToken)
?? throw CoreException.CreateByCode(CoreExceptionCode.NotFound);

var entityToUpdate = sectionFound.MapToEntity();

entityToUpdate.UpdateCurrentDaysCount(entityToUpdate.CurrentDaysCount)
.EnsureSuccess();

await using var transaction = await _context.Database.BeginTransactionAsync(cancellationToken);

var affetedRows = await _context
.TrainingSections
.Where(e => e.Id == periodToUpdate.SectionId)
.Where(e => e.ConcurrencyStamp == entityToUpdate.ConcurrencyStamp)
.ExecuteUpdateAsync(setter => setter.SetProperty(p => p.CurrentDaysCount, entityToUpdate.CurrentDaysCount));

periodToUpdate.EndedAt = periodEntity.EndedAt;
periodToUpdate.UpdatedAt = periodEntity.UpdatedAt;
periodToUpdate.StartedAt = periodEntity.StartedAt;
periodToUpdate.Observation = periodEntity.Observation;

if (affetedRows != 0)
throw CoreException.CreateByCode(CoreExceptionCode.ThisEntityWasAlreadyUpdateByAnotherSource);

await _context.SaveChangesAsync();
await transaction.CommitAsync();

return new();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Bl.Gym.TrainingApi.Application.Commands.Training.FinishTrainingPeriod;

public record FinishTrainingPeriodRequest(
Guid PeriodId)
: IRequest<FinishTrainingPeriodResponse>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Bl.Gym.TrainingApi.Application.Commands.Training.FinishTrainingPeriod;

public record FinishTrainingPeriodResponse();
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

namespace Bl.Gym.TrainingApi.Application.Commands.Training.GetTrainingInfoById;

/// <summary>
/// Get all the data about the training section by ID.
/// </summary>
public class GetTrainingInfoByIdHandler
: IRequestHandler<GetTrainingInfoByIdRequest, GetTrainingInfoByIdResponse>
{
Expand Down Expand Up @@ -67,6 +70,19 @@ on sets.ExerciseId equals exercises.Id
/*CreatedAt: */exercises.CreatedAt))
.ToListAsync(cancellationToken);

var periodsTrained = await
_context
.TrainingsPeriod
.AsNoTracking()
.Where(e => e.SectionId == sectionById.SectionId)
.Select(e => new GetTrainingInfoByIdResponsePeriod(
/*Id*/ e.Id,
/*StartedAt*/ e.StartedAt,
/*EndedAt*/ e.EndedAt,
/*Obs*/ e.Observation,
/*Completed*/ e.EndedAt != null))
.ToListAsync(cancellationToken);

sectionById = sectionById with
{
//
Expand All @@ -78,6 +94,7 @@ on sets.ExerciseId equals exercises.Id
return new GetTrainingInfoByIdResponse(
Section: sectionById,
Status: trainingGym.Status.ToString(),
Periods: periodsTrained,
CreatedAt: trainingGym.CreatedAt
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Bl.Gym.TrainingApi.Application.Commands.Training.GetTrainingInfoById;
/// <param name="Sections"></param>
public record GetTrainingInfoByIdResponse(
GetTrainingInfoByIdResponseSection Section,
IEnumerable<GetTrainingInfoByIdResponsePeriod> Periods,
string Status,
DateTimeOffset CreatedAt);

Expand All @@ -24,6 +25,14 @@ public record GetTrainingInfoByIdResponseSection(
DateTimeOffset CreatedAt)
;

public record GetTrainingInfoByIdResponsePeriod(
Guid Id,
DateTime? StartedAt,
DateTime? EndedAt,
string? Obs,
bool Completed)
;

public record GetTrainingInfoByIdResponseExerciseSet(
string Set,
string Title,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@

using Bl.Gym.TrainingApi.Application.Model.Training;
using Bl.Gym.TrainingApi.Application.Providers;
using Bl.Gym.TrainingApi.Application.Repositories;
using Bl.Gym.TrainingApi.Application.Services;
using Bl.Gym.TrainingApi.Domain.Entities.Training;

namespace Bl.Gym.TrainingApi.Application.Commands.Training.StartTrainingPeriod;

public class StartTrainingPeriodHandler
: IRequestHandler<StartTrainingPeriodRequest, StartTrainingPeriodResponse>
{
private readonly TrainingContext _trainingContext;
private readonly GymRoleCheckerService _gymRoleCheckerService;
private readonly IIdentityProvider _identityProvider;
private readonly ILogger<StartTrainingPeriodHandler> _logger;

public StartTrainingPeriodHandler(
TrainingContext trainingContext,
GymRoleCheckerService gymRoleCheckerService,
IIdentityProvider identityProvider,
ILogger<StartTrainingPeriodHandler> logger)
{
_trainingContext = trainingContext;
_gymRoleCheckerService = gymRoleCheckerService;
_identityProvider = identityProvider;
_logger = logger;
}

public async Task<StartTrainingPeriodResponse> Handle(
StartTrainingPeriodRequest request,
CancellationToken cancellationToken)
{
var user = await _identityProvider.GetCurrentAsync(cancellationToken);

var userId = user.RequiredUserId();

var containsLastNotFinished = await _trainingContext
.TrainingsPeriod
.AsNoTracking()
.Where(e => e.UserId == userId)
.Where(e => e.EndedAt == null)
.AnyAsync(cancellationToken);

if (containsLastNotFinished)
{
_logger.LogInformation("There is already an opened training period to user {0}.", userId);
throw CoreException.CreateByCode(CoreExceptionCode.Conflict);
}

await _gymRoleCheckerService.ThrowIfUserIsntInTheSectionAsync(userId, request.TrainingSectionId, cancellationToken);

var entity = TrainingUserPeriod.Create(
id: Guid.NewGuid(),
userId: userId,
sectionId: request.TrainingSectionId,
startedAt: DateTime.UtcNow,
endedAt: null,
observation: string.Empty,
createdAt: DateTime.UtcNow,
updatedAt: DateTime.UtcNow)
.RequiredResult;

var entityResult = await _trainingContext
.TrainingsPeriod
.AddAsync(TrainingUserPeriodModel.MapFromEntity(entity), cancellationToken);

await _trainingContext.SaveChangesAsync();

return new(entityResult.Entity.Id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Bl.Gym.TrainingApi.Application.Commands.Training.StartTrainingPeriod;

public record StartTrainingPeriodRequest(
Guid TrainingSectionId)
: IRequest<StartTrainingPeriodResponse>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace Bl.Gym.TrainingApi.Application.Commands.Training.StartTrainingPeriod;

public record StartTrainingPeriodResponse(
Guid PeriodIdCreated);
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Bl.Gym.TrainingApi.Application.Commands.Training.UpdateCurrentDaysCountFromSection;

[Obsolete("Use 'FinishTrainingPeriodHandler'.")]
internal class UpdateCurrentDaysCountFromSectionHandler
: IRequestHandler<UpdateCurrentDaysCountFromSectionRequest, Guid>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Bl.Gym.TrainingApi.Application.Commands.Training.UpdateCurrentDaysCountFromSection;

[Obsolete("Use 'FinishTrainingPeriodHandler'.")]
public record UpdateCurrentDaysCountFromSectionRequest(
Guid SectionId,
int NewCurrentDaysCount)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Bl.Gym.TrainingApi.Domain.Entities.Identity;
using Bl.Gym.TrainingApi.Domain.Entities.Training;
using static System.Collections.Specialized.BitVector32;

namespace Bl.Gym.TrainingApi.Application.Model.Training;

/// <summary>
/// This model represents an relation between User and Training Section.
/// </summary>
public class TrainingUserPeriodModel
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public Guid SectionId { get; set; }

public DateTime? StartedAt { get; set; }
public DateTime? EndedAt { get; set; }
public string? Observation { get; set; }

public DateTime UpdatedAt { get; set; }
public DateTime CreatedAt { get; set; }

public TrainingUserPeriod MapToEntity()
{
return TrainingUserPeriod.Create(
id: Id,
userId: UserId,
sectionId: SectionId,
startedAt: StartedAt,
endedAt: EndedAt,
observation: Observation,
updatedAt: UpdatedAt,
createdAt: CreatedAt)
.RequiredResult;
}

public static TrainingUserPeriodModel MapFromEntity(TrainingUserPeriod entity)
{
return new()
{
CreatedAt = entity.CreatedAt,
Id = entity.Id,
EndedAt = entity.EndedAt,
Observation = entity.Observation,
SectionId = entity.SectionId,
StartedAt = entity.StartedAt,
UpdatedAt = entity.UpdatedAt,
UserId = entity.UserId,
};
}
}
Loading

0 comments on commit f469a80

Please sign in to comment.