From 461a3b759e8567ec8a27804c2c3088eb4858a490 Mon Sep 17 00:00:00 2001 From: sanchezvem Date: Wed, 11 Mar 2026 22:04:21 +0100 Subject: [PATCH] Added endpoints to generate challenges --- BeReadyBackend.sln.DotSettings | 2 + BeReadyBackend/BeReadyBackend.csproj | 4 -- .../RandomChallenges/GetRandomChallengeDto.cs | 9 +++ .../GenerateRandomChallengeEndpoint.cs | 55 +++++++++++++++++- .../GetRandomChallengeEndpoint.cs | 45 ++++++++++++++- .../RandomChallenges/PatchProofEndpoint.cs | 57 ++++++++++++++++++- .../Users/GetAllUserChallengesEndpoint.cs | 11 +++- .../Users/GetAllUserProofsEndpoint.cs | 11 +++- .../MappingProfiles/EntityToDtoMappings.cs | 3 + .../GetRandomChallengeByCriteriaSpec.cs | 13 +++++ .../GetRandomChallengeByIdSpec.cs | 13 +++++ .../GetRandomChallengesNotAlreadyPastSpec.cs | 13 +++++ .../Specifications/Users/GetAllUsersSpec.cs | 13 +++++ 13 files changed, 233 insertions(+), 16 deletions(-) create mode 100644 BeReadyBackend.sln.DotSettings create mode 100644 BeReadyBackend/DTO/RandomChallenges/GetRandomChallengeDto.cs create mode 100644 BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengeByCriteriaSpec.cs create mode 100644 BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengeByIdSpec.cs create mode 100644 BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengesNotAlreadyPastSpec.cs create mode 100644 BeReadyBackend/Specifications/Users/GetAllUsersSpec.cs diff --git a/BeReadyBackend.sln.DotSettings b/BeReadyBackend.sln.DotSettings new file mode 100644 index 0000000..3d8771c --- /dev/null +++ b/BeReadyBackend.sln.DotSettings @@ -0,0 +1,2 @@ + + False \ No newline at end of file diff --git a/BeReadyBackend/BeReadyBackend.csproj b/BeReadyBackend/BeReadyBackend.csproj index a7df42c..37a2e8d 100644 --- a/BeReadyBackend/BeReadyBackend.csproj +++ b/BeReadyBackend/BeReadyBackend.csproj @@ -27,8 +27,4 @@ - - - - diff --git a/BeReadyBackend/DTO/RandomChallenges/GetRandomChallengeDto.cs b/BeReadyBackend/DTO/RandomChallenges/GetRandomChallengeDto.cs new file mode 100644 index 0000000..4b02011 --- /dev/null +++ b/BeReadyBackend/DTO/RandomChallenges/GetRandomChallengeDto.cs @@ -0,0 +1,9 @@ +namespace BeReadyBackend.DTO.RandomChallenges; + +public class GetRandomChallengeDto +{ + public int Id { get; set; } + public string? Libelle { get; set; } + public int Duration { get; set; } + public bool IsAlreadyPast { get; set; } +} \ No newline at end of file diff --git a/BeReadyBackend/Endpoints/RandomChallenges/GenerateRandomChallengeEndpoint.cs b/BeReadyBackend/Endpoints/RandomChallenges/GenerateRandomChallengeEndpoint.cs index 1012931..f9f3805 100644 --- a/BeReadyBackend/Endpoints/RandomChallenges/GenerateRandomChallengeEndpoint.cs +++ b/BeReadyBackend/Endpoints/RandomChallenges/GenerateRandomChallengeEndpoint.cs @@ -1,6 +1,55 @@ -namespace BeReadyBackend.Endpoints.RandomChallenges; +using BeReadyBackend.Models; +using BeReadyBackend.Repositories; +using BeReadyBackend.Specifications.RandomChallenges; +using BeReadyBackend.Specifications.Users; +using FastEndpoints; -public class GenerateRandomChallengeEndpoint +namespace BeReadyBackend.Endpoints.RandomChallenges; + +public class GenerateRandomChallengeEndpoint( + RandomChallengesRepository randomChallengesRepository, + UserRandomChallengesRepository userRandomChallengesRepository, + UsersRepository usersRepository) + : EndpointWithoutRequest { - + public override void Configure() + { + Post("/RandomChallenges/"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + RandomChallenge? randomChallenge = await randomChallengesRepository.FirstOrDefaultAsync(new GetRandomChallengesNotAlreadyPastSpec(), ct); + if (randomChallenge is null) + { + await Send.StringAsync("Il n'y a plus de défis en stock", 500, cancellation: ct); + return; + } + + List userList = await usersRepository.ListAsync(new GetAllUsersSpec(), ct); + + // foreach (User user in userList) + // { + // UserRandomChallenge userRandomChallenge = new() + // { + // UserId = user.Id, + // RandomChallengeId = randomChallenge.Id + // }; + // + // await userRandomChallengesRepository.AddAsync(userRandomChallenge, ct); + // } + + List userRandomChallenges = userList.Select(user => new UserRandomChallenge + { + UserId = user.Id, + RandomChallengeId = randomChallenge.Id + }).ToList(); + + await userRandomChallengesRepository.AddRangeAsync(userRandomChallenges, ct); + + randomChallenge.IsAlreadyPast = true; + await randomChallengesRepository.SaveChangesAsync(ct); + + await Send.NoContentAsync(ct); + } } \ No newline at end of file diff --git a/BeReadyBackend/Endpoints/RandomChallenges/GetRandomChallengeEndpoint.cs b/BeReadyBackend/Endpoints/RandomChallenges/GetRandomChallengeEndpoint.cs index a4a0456..8acba33 100644 --- a/BeReadyBackend/Endpoints/RandomChallenges/GetRandomChallengeEndpoint.cs +++ b/BeReadyBackend/Endpoints/RandomChallenges/GetRandomChallengeEndpoint.cs @@ -1,6 +1,45 @@ -namespace BeReadyBackend.Endpoints.RandomChallenges; +using BeReadyBackend.DTO.RandomChallenges; +using BeReadyBackend.Models; +using BeReadyBackend.Repositories; +using BeReadyBackend.Services; +using BeReadyBackend.Specifications.RandomChallenges; +using FastEndpoints; -public class GetRandomChallengeEndpoint +namespace BeReadyBackend.Endpoints.RandomChallenges; + +public class GetRandomChallengeRequest { - + public int RandomChallengeId { get; set; } +} + +public class GetRandomChallengeEndpoint( + RandomChallengesRepository randomChallengesRepository, + UserRandomChallengesRepository userRandomChallengesRepository, + UserService usersService) + : Endpoint +{ + public override void Configure() + { + Get("/RandomChallenges/{@RandomChallengeId}", x => new { x.RandomChallengeId }); + } + + public override async Task HandleAsync(GetRandomChallengeRequest req, CancellationToken ct) + { + int userId = usersService.GetUserIdFromToken(); + UserRandomChallenge? randomChallenge = await userRandomChallengesRepository.SingleOrDefaultAsync(new GetRandomChallengeByCriteriaSpec(req.RandomChallengeId, userId), ct); + + if (randomChallenge is null) + { + await Send.NotFoundAsync(ct); + return; + } + + if (randomChallenge.Proof is not null) + { + await Send.StringAsync("Preuve déjà déposée", 400, cancellation: ct); + return; + } + + await Send.OkAsync(await randomChallengesRepository.ProjectToSingleAsync(new GetRandomChallengeByIdSpec(req.RandomChallengeId), ct), ct); + } } \ No newline at end of file diff --git a/BeReadyBackend/Endpoints/RandomChallenges/PatchProofEndpoint.cs b/BeReadyBackend/Endpoints/RandomChallenges/PatchProofEndpoint.cs index aa1c44c..032fbf6 100644 --- a/BeReadyBackend/Endpoints/RandomChallenges/PatchProofEndpoint.cs +++ b/BeReadyBackend/Endpoints/RandomChallenges/PatchProofEndpoint.cs @@ -1,5 +1,58 @@ -namespace BeReadyBackend.Endpoints.RandomChallenges; +using BeReadyBackend.Models; +using BeReadyBackend.Repositories; +using BeReadyBackend.Services; +using BeReadyBackend.Specifications.RandomChallenges; +using BeReadyBackend.Specifications.Users; +using FastEndpoints; -public class PatchProofEndpoint +namespace BeReadyBackend.Endpoints.RandomChallenges; + +public class RandomChallengeProofRequest { + public int RandomChallengeId { get; set; } + public string? Proof { get; set; } +} + +public class PatchProofEndpoint( + UsersRepository usersRepository, + UserRandomChallengesRepository userRandomChallengesRepository, + UserService userService, + AutoMapper.IMapper mapper) : Endpoint +{ + public override void Configure() + { + Patch("/RandomChallenge/{@RandomChallengeId}/Proof", x => new { x.RandomChallengeId }); + } + + public override async Task HandleAsync(RandomChallengeProofRequest req, CancellationToken ct) + { + int userId = userService.GetUserIdFromToken(); + + UserRandomChallenge? userRandomChallenge = + await userRandomChallengesRepository.SingleOrDefaultAsync(new GetRandomChallengeByCriteriaSpec(req.RandomChallengeId, userId), ct); + if (userRandomChallenge is null) + { + await Send.NotFoundAsync(ct); + return; + } + + if (userRandomChallenge.Proof is not null) + { + await Send.StringAsync("Vous avez déjà déposé une preuve",400, cancellation:ct); + return; + } + + User? user = await usersRepository.SingleOrDefaultAsync(new GetUserByIdSpec(userId), ct); + if (user is null) + { + await Send.NotFoundAsync(ct); + return; + } + + mapper.Map(req, userRandomChallenge); + user.Score++; // 1pts bonus + + await userRandomChallengesRepository.SaveChangesAsync(ct); + await Send.NoContentAsync(ct); + } } \ No newline at end of file diff --git a/BeReadyBackend/Endpoints/Users/GetAllUserChallengesEndpoint.cs b/BeReadyBackend/Endpoints/Users/GetAllUserChallengesEndpoint.cs index 21c9893..d0230e1 100644 --- a/BeReadyBackend/Endpoints/Users/GetAllUserChallengesEndpoint.cs +++ b/BeReadyBackend/Endpoints/Users/GetAllUserChallengesEndpoint.cs @@ -28,9 +28,16 @@ public class GetAllUserChallengesEndpoint(UsersRepository usersRepository, UserS List challenges = []; if (user.UserRandomChallenges is not null) - challenges.AddRange(user.UserRandomChallenges.Select(x => mapper.Map(x.RandomChallenge))); + challenges.AddRange( + user.UserRandomChallenges + .Where(x => x.Proof is not null) + .Select(x => mapper.Map(x.RandomChallenge)) + ); + if (user.UserGroups is not null) - challenges.AddRange(user.UserGroups.Select(x => mapper.Map(x.Group))); + challenges.AddRange( + user.UserGroups.Select(x => mapper.Map(x.Group)) + ); await Send.OkAsync(challenges, ct); } diff --git a/BeReadyBackend/Endpoints/Users/GetAllUserProofsEndpoint.cs b/BeReadyBackend/Endpoints/Users/GetAllUserProofsEndpoint.cs index baa0a1d..30c0f3d 100644 --- a/BeReadyBackend/Endpoints/Users/GetAllUserProofsEndpoint.cs +++ b/BeReadyBackend/Endpoints/Users/GetAllUserProofsEndpoint.cs @@ -28,9 +28,16 @@ public class GetAllUserProofsEndpoint(UsersRepository usersRepository, UserServi List proofs = []; if (user.UserRandomChallenges is not null) - proofs.AddRange(user.UserRandomChallenges.Select(x => mapper.Map(x.RandomChallenge))); + proofs.AddRange( + user.UserRandomChallenges + .Where(x => x.Proof is not null) + .Select(x => mapper.Map(x.RandomChallenge)) + ); + if (user.UserGroups is not null) - proofs.AddRange(user.UserGroups.Select(x => mapper.Map(x.Group))); + proofs.AddRange( + user.UserGroups.Select(x => mapper.Map(x.Group)) + ); await Send.OkAsync(proofs, ct); } diff --git a/BeReadyBackend/MappingProfiles/EntityToDtoMappings.cs b/BeReadyBackend/MappingProfiles/EntityToDtoMappings.cs index 8661041..4d6ed08 100644 --- a/BeReadyBackend/MappingProfiles/EntityToDtoMappings.cs +++ b/BeReadyBackend/MappingProfiles/EntityToDtoMappings.cs @@ -3,6 +3,7 @@ using BeReadyBackend.DTO.Achievements; using BeReadyBackend.DTO.Friends; using BeReadyBackend.DTO.Groups; using BeReadyBackend.DTO.Messages; +using BeReadyBackend.DTO.RandomChallenges; using BeReadyBackend.DTO.Users; using BeReadyBackend.Models; @@ -69,5 +70,7 @@ public class EntityToDtoMappings : Profile CreateMap() .ForMember(dest => dest.Username, opt => opt.MapFrom(src => src.User!.Username)); + + CreateMap(); } } \ No newline at end of file diff --git a/BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengeByCriteriaSpec.cs b/BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengeByCriteriaSpec.cs new file mode 100644 index 0000000..52d5cde --- /dev/null +++ b/BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengeByCriteriaSpec.cs @@ -0,0 +1,13 @@ +using Ardalis.Specification; +using BeReadyBackend.Models; + +namespace BeReadyBackend.Specifications.RandomChallenges; + +public class GetRandomChallengeByCriteriaSpec : SingleResultSpecification +{ + public GetRandomChallengeByCriteriaSpec(int challengeId, int userId) + { + Query + .Where(x => x.RandomChallengeId == challengeId && x.UserId == userId); + } +} \ No newline at end of file diff --git a/BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengeByIdSpec.cs b/BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengeByIdSpec.cs new file mode 100644 index 0000000..c985ef7 --- /dev/null +++ b/BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengeByIdSpec.cs @@ -0,0 +1,13 @@ +using Ardalis.Specification; +using BeReadyBackend.Models; + +namespace BeReadyBackend.Specifications.RandomChallenges; + +public class GetRandomChallengeByIdSpec : SingleResultSpecification +{ + public GetRandomChallengeByIdSpec(int randomChallengeId) + { + Query + .Where(x => x.Id == randomChallengeId); + } +} \ No newline at end of file diff --git a/BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengesNotAlreadyPastSpec.cs b/BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengesNotAlreadyPastSpec.cs new file mode 100644 index 0000000..4f82514 --- /dev/null +++ b/BeReadyBackend/Specifications/RandomChallenges/GetRandomChallengesNotAlreadyPastSpec.cs @@ -0,0 +1,13 @@ +using Ardalis.Specification; +using BeReadyBackend.Models; + +namespace BeReadyBackend.Specifications.RandomChallenges; + +public class GetRandomChallengesNotAlreadyPastSpec : Specification +{ + public GetRandomChallengesNotAlreadyPastSpec() + { + Query + .Where(x => !x.IsAlreadyPast); + } +} \ No newline at end of file diff --git a/BeReadyBackend/Specifications/Users/GetAllUsersSpec.cs b/BeReadyBackend/Specifications/Users/GetAllUsersSpec.cs new file mode 100644 index 0000000..bcd97f9 --- /dev/null +++ b/BeReadyBackend/Specifications/Users/GetAllUsersSpec.cs @@ -0,0 +1,13 @@ +using Ardalis.Specification; +using BeReadyBackend.Models; + +namespace BeReadyBackend.Specifications.Users; + +public class GetAllUsersSpec : Specification +{ + public GetAllUsersSpec() + { + Query + .Where(x => x.Id != 0); + } +} \ No newline at end of file