Compare commits
6 Commits
75876b3ab3
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b5f18d486 | |||
| 2116737987 | |||
| df59a97d4f | |||
| e1c505e7a1 | |||
| 76cbe90521 | |||
| bb1120f967 |
@@ -1,6 +1,8 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEndpoint_002ESend_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fc2fa49f697e4d07c58aa3f35484a5103de685287155db8b628f2cdce16b69_003FEndpoint_002ESend_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEndpoint_002ESend_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fc2fa49f697e4d07c58aa3f35484a5103de685287155db8b628f2cdce16b69_003FEndpoint_002ESend_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEndpoint_002ESetup_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F656240c46e44c14018dc6190e77764a3404d76b559ed75474669c553eb6227dd_003FEndpoint_002ESetup_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEndpoint_002ESetup_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F656240c46e44c14018dc6190e77764a3404d76b559ed75474669c553eb6227dd_003FEndpoint_002ESetup_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIConfiguration_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F17a3a8d481919bdc3f1630b5a7deadb2cd394fa12fff3312e6abe29bfc4_003FIConfiguration_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIFormFile_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4d6d6283215de958b1baadc74d6f99ce76f43090cfc86e26e51d845b779450_003FIFormFile_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIHubClients_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fd6ae5218e3a0462f8a94591a77a902637b750_003Faf_003F6ad738e4_003FIHubClients_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIHubClients_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fd6ae5218e3a0462f8a94591a77a902637b750_003Faf_003F6ad738e4_003FIHubClients_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIHubContext_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F731dbe51d65849048244493644b992cd78910_003Fda_003Fd14ae6ee_003FIHubContext_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIHubContext_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F731dbe51d65849048244493644b992cd78910_003Fda_003Fd14ae6ee_003FIHubContext_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARepositoryBaseOfT_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F5023b5be698d783ffe9f42b2e944a85a7a66b61bc5e19c76c591036343fd16_003FRepositoryBaseOfT_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARepositoryBaseOfT_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F5023b5be698d783ffe9f42b2e944a85a7a66b61bc5e19c76c591036343fd16_003FRepositoryBaseOfT_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<PackageReference Include="Ardalis.Specification.EntityFrameworkCore" Version="9.3.1" />
|
<PackageReference Include="Ardalis.Specification.EntityFrameworkCore" Version="9.3.1" />
|
||||||
<PackageReference Include="AutoMapper" Version="16.0.0" />
|
<PackageReference Include="AutoMapper" Version="16.0.0" />
|
||||||
<PackageReference Include="AutoMapper.Collection" Version="13.0.0" />
|
<PackageReference Include="AutoMapper.Collection" Version="13.0.0" />
|
||||||
|
<PackageReference Include="AWSSDK.S3" Version="4.0.24" />
|
||||||
<PackageReference Include="BCrypt.Net-Next" Version="4.1.0" />
|
<PackageReference Include="BCrypt.Net-Next" Version="4.1.0" />
|
||||||
<PackageReference Include="FastEndpoints" Version="7.2.0" />
|
<PackageReference Include="FastEndpoints" Version="7.2.0" />
|
||||||
<PackageReference Include="FastEndpoints.Security" Version="7.2.0" />
|
<PackageReference Include="FastEndpoints.Security" Version="7.2.0" />
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class LoginEndpoint(UsersRepository usersRepository, AutoMapper.IMapper m
|
|||||||
{
|
{
|
||||||
string jwtToken = JwtBearer.CreateToken(o =>
|
string jwtToken = JwtBearer.CreateToken(o =>
|
||||||
{
|
{
|
||||||
o.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong";
|
o.SigningKey = "v9!Qx7#Lk2@pZ8$wR6!tN5%uF3&cD9^mH1*eY4";
|
||||||
o.ExpireAt = DateTime.UtcNow.AddDays(15);
|
o.ExpireAt = DateTime.UtcNow.AddDays(15);
|
||||||
o.User.Claims.Add(("Username", user.Username)!);
|
o.User.Claims.Add(("Username", user.Username)!);
|
||||||
o.User.Claims.Add(("FullName", user.FirstName + user.Name));
|
o.User.Claims.Add(("FullName", user.FirstName + user.Name));
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class RefreshTokenEndpoint(UsersRepository usersRepository, AutoMapper.IM
|
|||||||
|
|
||||||
string jwtToken = JwtBearer.CreateToken(o =>
|
string jwtToken = JwtBearer.CreateToken(o =>
|
||||||
{
|
{
|
||||||
o.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong";
|
o.SigningKey = "v9!Qx7#Lk2@pZ8$wR6!tN5%uF3&cD9^mH1*eY4";
|
||||||
o.ExpireAt = DateTime.UtcNow.AddDays(15);
|
o.ExpireAt = DateTime.UtcNow.AddDays(15);
|
||||||
o.User.Claims.Add(("Username", user.Username)!);
|
o.User.Claims.Add(("Username", user.Username)!);
|
||||||
o.User.Claims.Add(("FullName", user.FirstName + user.Name));
|
o.User.Claims.Add(("FullName", user.FirstName + user.Name));
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using FastEndpoints;
|
|||||||
|
|
||||||
namespace BeReadyBackend.Endpoints.Posts;
|
namespace BeReadyBackend.Endpoints.Posts;
|
||||||
|
|
||||||
public class GetAllPostsEndpoint(PostsRepository postsRepository, UserService userService) : EndpointWithoutRequest<List<GetPostDto>>
|
public class GetAllPostsEndpoint(PostsRepository postsRepository, UserService userService, StorageService storageService) : EndpointWithoutRequest<List<GetPostDto>>
|
||||||
{
|
{
|
||||||
public override void Configure()
|
public override void Configure()
|
||||||
{
|
{
|
||||||
@@ -20,20 +20,25 @@ public class GetAllPostsEndpoint(PostsRepository postsRepository, UserService us
|
|||||||
|
|
||||||
List<Post> posts = await postsRepository.ListAsync(new GetPostNotMeSpec(userId), ct);
|
List<Post> posts = await postsRepository.ListAsync(new GetPostNotMeSpec(userId), ct);
|
||||||
|
|
||||||
List<GetPostDto> result = posts.Select(x => new GetPostDto
|
List<GetPostDto> result = posts.Select(x =>
|
||||||
|
{
|
||||||
|
string? proof = x.User?.UserRandomChallenges?
|
||||||
|
.SingleOrDefault(u =>
|
||||||
|
u.RandomChallenge?.GeneratedAt is not null
|
||||||
|
&& DateOnly.FromDateTime(u.RandomChallenge.GeneratedAt.Value) == DateOnly.FromDateTime(x.CreationDate))
|
||||||
|
?.Proof;
|
||||||
|
|
||||||
|
return new GetPostDto
|
||||||
{
|
{
|
||||||
Id = x.Id,
|
Id = x.Id,
|
||||||
Libelle = x.Libelle,
|
Libelle = x.Libelle,
|
||||||
CreationDate = x.CreationDate,
|
CreationDate = x.CreationDate,
|
||||||
Likes = x.Likes,
|
Likes = x.Likes,
|
||||||
Proof = x.User?.UserRandomChallenges?
|
Proof = proof is not null ? storageService.GetUrl(proof) : null,
|
||||||
.SingleOrDefault(u =>
|
|
||||||
u.RandomChallenge?.GeneratedAt is not null
|
|
||||||
&& DateOnly.FromDateTime(u.RandomChallenge.GeneratedAt.Value) == DateOnly.FromDateTime(x.CreationDate))
|
|
||||||
?.Proof,
|
|
||||||
UserId = x.UserId,
|
UserId = x.UserId,
|
||||||
Username = x.User?.Username,
|
Username = x.User?.Username,
|
||||||
IsLiked = x.UserPosts?.Count(y => y.UserId == userId) > 0
|
IsLiked = x.UserPosts?.Count(y => y.UserId == userId) > 0
|
||||||
|
};
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
await Send.OkAsync(result, ct);
|
await Send.OkAsync(result, ct);
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ public class RandomChallengeProofRequest
|
|||||||
public class PatchProofEndpoint(
|
public class PatchProofEndpoint(
|
||||||
UsersRepository usersRepository,
|
UsersRepository usersRepository,
|
||||||
UserRandomChallengesRepository userRandomChallengesRepository,
|
UserRandomChallengesRepository userRandomChallengesRepository,
|
||||||
UserService userService,
|
|
||||||
RandomChallengesRepository randomChallengesRepository,
|
RandomChallengesRepository randomChallengesRepository,
|
||||||
PostsRepository postsRepository) : Endpoint<RandomChallengeProofRequest>
|
PostsRepository postsRepository,
|
||||||
|
UserService userService,
|
||||||
|
StorageService storageService) : Endpoint<RandomChallengeProofRequest>
|
||||||
{
|
{
|
||||||
public override void Configure()
|
public override void Configure()
|
||||||
{
|
{
|
||||||
@@ -70,13 +71,9 @@ public class PatchProofEndpoint(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encodage en base64
|
string key = await storageService.UploadFile(req.Proof, $"random-challenges/{req.RandomChallengeId}/{userId}", ct);
|
||||||
using MemoryStream memoryStream = new();
|
|
||||||
await req.Proof.CopyToAsync(memoryStream, ct);
|
|
||||||
byte[] proofBytes = memoryStream.ToArray();
|
|
||||||
|
|
||||||
userRandomChallenge.Proof = Convert.ToBase64String(proofBytes);
|
|
||||||
|
|
||||||
|
userRandomChallenge.Proof = key;
|
||||||
user.TotalChallenge++;
|
user.TotalChallenge++;
|
||||||
|
|
||||||
UserRandomChallenge? lastChallenge = await userRandomChallengesRepository.SingleOrDefaultAsync(new GetLastRandomChallengeSpec(userId), ct);
|
UserRandomChallenge? lastChallenge = await userRandomChallengesRepository.SingleOrDefaultAsync(new GetLastRandomChallengeSpec(userId), ct);
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
using BeReadyBackend.DTO.Users;
|
using BeReadyBackend.DTO.Users;
|
||||||
using BeReadyBackend.Models;
|
using BeReadyBackend.Models;
|
||||||
using BeReadyBackend.Repositories;
|
using BeReadyBackend.Repositories;
|
||||||
|
using BeReadyBackend.Specifications.RandomChallenges;
|
||||||
using BeReadyBackend.Specifications.Users;
|
using BeReadyBackend.Specifications.Users;
|
||||||
using FastEndpoints;
|
using FastEndpoints;
|
||||||
using PasswordGenerator;
|
using PasswordGenerator;
|
||||||
|
|
||||||
namespace BeReadyBackend.Endpoints.Users;
|
namespace BeReadyBackend.Endpoints.Users;
|
||||||
|
|
||||||
public class CreateUserEndpoint(UsersRepository usersRepository, AutoMapper.IMapper mapper) : Endpoint<CreateUserDto>
|
public class CreateUserEndpoint(
|
||||||
|
UsersRepository usersRepository,
|
||||||
|
RandomChallengesRepository randomChallengesRepository,
|
||||||
|
UserRandomChallengesRepository userRandomChallengesRepository,
|
||||||
|
AutoMapper.IMapper mapper) : Endpoint<CreateUserDto>
|
||||||
{
|
{
|
||||||
public override void Configure()
|
public override void Configure()
|
||||||
{
|
{
|
||||||
@@ -33,6 +38,18 @@ public class CreateUserEndpoint(UsersRepository usersRepository, AutoMapper.IMap
|
|||||||
user.Password = BCrypt.Net.BCrypt.HashPassword(req.Password + salt);
|
user.Password = BCrypt.Net.BCrypt.HashPassword(req.Password + salt);
|
||||||
|
|
||||||
await usersRepository.AddAsync(user, ct);
|
await usersRepository.AddAsync(user, ct);
|
||||||
|
|
||||||
|
RandomChallenge? randomChallenge = await randomChallengesRepository.SingleOrDefaultAsync(new GetRandomChallengeByDateSpec(), ct);
|
||||||
|
if (randomChallenge is not null)
|
||||||
|
{
|
||||||
|
UserRandomChallenge userRandomChallenge = new()
|
||||||
|
{
|
||||||
|
UserId = user.Id,
|
||||||
|
RandomChallengeId = randomChallenge.Id
|
||||||
|
};
|
||||||
|
await userRandomChallengesRepository.AddAsync(userRandomChallenge, ct);
|
||||||
|
}
|
||||||
|
|
||||||
await Send.NoContentAsync(ct);
|
await Send.NoContentAsync(ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,12 +2,13 @@
|
|||||||
using BeReadyBackend.Models;
|
using BeReadyBackend.Models;
|
||||||
using BeReadyBackend.Repositories;
|
using BeReadyBackend.Repositories;
|
||||||
using BeReadyBackend.Services;
|
using BeReadyBackend.Services;
|
||||||
using BeReadyBackend.Specifications.Users;
|
using BeReadyBackend.Specifications.RandomChallenges;
|
||||||
using FastEndpoints;
|
using FastEndpoints;
|
||||||
|
|
||||||
namespace BeReadyBackend.Endpoints.Users;
|
namespace BeReadyBackend.Endpoints.Users;
|
||||||
|
|
||||||
public class GetAllUserChallengesEndpoint(UsersRepository usersRepository, UserService userService, AutoMapper.IMapper mapper) : EndpointWithoutRequest<List<GetUserChallengeDto>>
|
public class GetAllUserChallengesEndpoint(UserRandomChallengesRepository userRandomChallengesRepository, UserService userService, AutoMapper.IMapper mapper)
|
||||||
|
: EndpointWithoutRequest<List<GetUserChallengeDto>>
|
||||||
{
|
{
|
||||||
public override void Configure()
|
public override void Configure()
|
||||||
{
|
{
|
||||||
@@ -18,18 +19,11 @@ public class GetAllUserChallengesEndpoint(UsersRepository usersRepository, UserS
|
|||||||
{
|
{
|
||||||
int userId = userService.GetUserIdFromToken();
|
int userId = userService.GetUserIdFromToken();
|
||||||
|
|
||||||
User? user = await usersRepository.SingleOrDefaultAsync(new GetProofOrChallengeByUserIdSpec(userId), ct);
|
List<UserRandomChallenge>? userRandomChallenge = await userRandomChallengesRepository.ListAsync(new GetUserRandomChallengeByIdSpec(userId), ct);
|
||||||
|
|
||||||
if (user is null)
|
List<GetUserChallengeDto> challenges = userRandomChallenge
|
||||||
{
|
|
||||||
await Send.NotFoundAsync(ct);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GetUserChallengeDto> challenges = user.UserRandomChallenges?
|
|
||||||
.Where(x => x.Proof is not null)
|
|
||||||
.Select(x => mapper.Map<GetUserChallengeDto>(x.RandomChallenge))
|
.Select(x => mapper.Map<GetUserChallengeDto>(x.RandomChallenge))
|
||||||
.ToList() ?? [];
|
.ToList();
|
||||||
|
|
||||||
await Send.OkAsync(challenges.OrderByDescending(x => x.ChallengeStartDate).ToList(), ct);
|
await Send.OkAsync(challenges.OrderByDescending(x => x.ChallengeStartDate).ToList(), ct);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ using FastEndpoints;
|
|||||||
|
|
||||||
namespace BeReadyBackend.Endpoints.Users;
|
namespace BeReadyBackend.Endpoints.Users;
|
||||||
|
|
||||||
public class GetAllUserProofsEndpoint(UsersRepository usersRepository, UserService userService) : EndpointWithoutRequest<List<GetUserProofDto>>
|
public class GetAllUserProofsEndpoint(UserRandomChallengesRepository userRandomChallengesRepository, UserService userService, StorageService storageService)
|
||||||
|
: EndpointWithoutRequest<List<GetUserProofDto>>
|
||||||
{
|
{
|
||||||
public override void Configure()
|
public override void Configure()
|
||||||
{
|
{
|
||||||
@@ -18,21 +19,14 @@ public class GetAllUserProofsEndpoint(UsersRepository usersRepository, UserServi
|
|||||||
{
|
{
|
||||||
int userId = userService.GetUserIdFromToken();
|
int userId = userService.GetUserIdFromToken();
|
||||||
|
|
||||||
User? user = await usersRepository.SingleOrDefaultAsync(new GetProofOrChallengeByUserIdSpec(userId), ct);
|
List<UserRandomChallenge> userProofs = await userRandomChallengesRepository.ListAsync(new GetUserProofByUserIdSpec(userId), ct);
|
||||||
|
|
||||||
if (user is null)
|
List<GetUserProofDto> proofs = userProofs
|
||||||
{
|
|
||||||
await Send.NotFoundAsync(ct);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GetUserProofDto> proofs = user.UserRandomChallenges?
|
|
||||||
.Where(x => x.Proof is not null)
|
|
||||||
.Select(x => new GetUserProofDto
|
.Select(x => new GetUserProofDto
|
||||||
{
|
{
|
||||||
Proof = x.Proof
|
Proof = storageService.GetUrl(x.Proof!)
|
||||||
})
|
})
|
||||||
.ToList() ?? [];
|
.ToList();
|
||||||
|
|
||||||
await Send.OkAsync(proofs, ct);
|
await Send.OkAsync(proofs, ct);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ public class EntityToDtoMappings : Profile
|
|||||||
|
|
||||||
CreateMap<User, GetUserStatsDto>();
|
CreateMap<User, GetUserStatsDto>();
|
||||||
|
|
||||||
CreateMap<UserGroup, GetUserProofDto>();
|
|
||||||
CreateMap<UserRandomChallenge, GetUserProofDto>();
|
CreateMap<UserRandomChallenge, GetUserProofDto>();
|
||||||
|
|
||||||
CreateMap<RandomChallenge, GetUserChallengeDto>()
|
CreateMap<RandomChallenge, GetUserChallengeDto>()
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
using Amazon.S3;
|
||||||
|
using Amazon.S3.Model;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using AutoMapper.EquivalencyExpression;
|
using AutoMapper.EquivalencyExpression;
|
||||||
using BeReadyBackend;
|
using BeReadyBackend;
|
||||||
using BeReadyBackend.Hubs;
|
using BeReadyBackend.Hubs;
|
||||||
using BeReadyBackend.MappingProfiles;
|
using BeReadyBackend.MappingProfiles;
|
||||||
using BeReadyBackend.Models;
|
|
||||||
using FastEndpoints;
|
using FastEndpoints;
|
||||||
using FastEndpoints.Swagger;
|
using FastEndpoints.Swagger;
|
||||||
using FastEndpoints.Security;
|
using FastEndpoints.Security;
|
||||||
@@ -15,7 +16,7 @@ WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
|||||||
|
|
||||||
// On ajoute ici FastEndpoints, un framework REPR et Swagger aux services disponibles dans le projet
|
// On ajoute ici FastEndpoints, un framework REPR et Swagger aux services disponibles dans le projet
|
||||||
builder.Services
|
builder.Services
|
||||||
.AddAuthenticationJwtBearer(s => s.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong")
|
.AddAuthenticationJwtBearer(s => s.SigningKey = "v9!Qx7#Lk2@pZ8$wR6!tN5%uF3&cD9^mH1*eY4")
|
||||||
.AddAuthorization()
|
.AddAuthorization()
|
||||||
.AddFastEndpoints()
|
.AddFastEndpoints()
|
||||||
.AddCors(options =>
|
.AddCors(options =>
|
||||||
@@ -53,6 +54,7 @@ builder.Services.AddHttpContextAccessor();
|
|||||||
|
|
||||||
builder.Services.AddScoped<UserService>();
|
builder.Services.AddScoped<UserService>();
|
||||||
builder.Services.AddScoped<AchievementService>();
|
builder.Services.AddScoped<AchievementService>();
|
||||||
|
builder.Services.AddScoped<StorageService>();
|
||||||
|
|
||||||
MapperConfiguration mappingConfig = new(mc =>
|
MapperConfiguration mappingConfig = new(mc =>
|
||||||
{
|
{
|
||||||
@@ -65,6 +67,31 @@ MapperConfiguration mappingConfig = new(mc =>
|
|||||||
AutoMapper.IMapper mapper = mappingConfig.CreateMapper();
|
AutoMapper.IMapper mapper = mappingConfig.CreateMapper();
|
||||||
builder.Services.AddSingleton(mapper);
|
builder.Services.AddSingleton(mapper);
|
||||||
|
|
||||||
|
// RUSTFS
|
||||||
|
IConfigurationSection config = builder.Configuration.GetSection("RustFS");
|
||||||
|
|
||||||
|
AmazonS3Client s3Client = new(
|
||||||
|
config["AccessKey"],
|
||||||
|
config["SecretKey"],
|
||||||
|
new AmazonS3Config
|
||||||
|
{
|
||||||
|
ServiceURL = config["ServiceUrl"],
|
||||||
|
ForcePathStyle = true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
ListBucketsResponse? buckets = await s3Client.ListBucketsAsync();
|
||||||
|
bool exist = buckets?.Buckets?.Any(x => x.BucketName == config["BucketName"]) == true;
|
||||||
|
if (!exist)
|
||||||
|
{
|
||||||
|
await s3Client.PutBucketAsync(new PutBucketRequest
|
||||||
|
{
|
||||||
|
BucketName = config["BucketName"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<IAmazonS3>(s3Client);
|
||||||
|
|
||||||
WebApplication app = builder.Build();
|
WebApplication app = builder.Build();
|
||||||
app.UseAuthentication()
|
app.UseAuthentication()
|
||||||
.UseAuthorization()
|
.UseAuthorization()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using BeReadyBackend.Repositories;
|
|||||||
using BeReadyBackend.Specifications.Achievements;
|
using BeReadyBackend.Specifications.Achievements;
|
||||||
using BeReadyBackend.Specifications.Friends;
|
using BeReadyBackend.Specifications.Friends;
|
||||||
using BeReadyBackend.Specifications.Posts;
|
using BeReadyBackend.Specifications.Posts;
|
||||||
|
using BeReadyBackend.Specifications.RandomChallenges;
|
||||||
using BeReadyBackend.Specifications.UserAchievements;
|
using BeReadyBackend.Specifications.UserAchievements;
|
||||||
using BeReadyBackend.Specifications.Users;
|
using BeReadyBackend.Specifications.Users;
|
||||||
|
|
||||||
@@ -13,7 +14,8 @@ public class AchievementService(
|
|||||||
AchievementsRepository achievementsRepository,
|
AchievementsRepository achievementsRepository,
|
||||||
UserAchievementsRepository userAchievementsRepository,
|
UserAchievementsRepository userAchievementsRepository,
|
||||||
UserPostsRepository userPostsRepository,
|
UserPostsRepository userPostsRepository,
|
||||||
UserFriendsRepository userFriendsRepository)
|
UserFriendsRepository userFriendsRepository,
|
||||||
|
UserRandomChallengesRepository userRandomChallengesRepository)
|
||||||
{
|
{
|
||||||
public async Task Unlock(int userId, int achievementId)
|
public async Task Unlock(int userId, int achievementId)
|
||||||
{
|
{
|
||||||
@@ -39,7 +41,7 @@ public class AchievementService(
|
|||||||
User? user = await usersRepository.SingleOrDefaultAsync(new GetUserByIdSpec(userId));
|
User? user = await usersRepository.SingleOrDefaultAsync(new GetUserByIdSpec(userId));
|
||||||
if (user is null) return;
|
if (user is null) return;
|
||||||
|
|
||||||
int challengesCounter = await usersRepository.CountAsync(new GetProofOrChallengeByUserIdSpec(userId));
|
int challengesCounter = await userRandomChallengesRepository.CountAsync(new GetUserRandomChallengeByIdSpec(userId));
|
||||||
int likedCounter = await userPostsRepository.CountAsync(new GetPostsLikedByUserSpec(userId));
|
int likedCounter = await userPostsRepository.CountAsync(new GetPostsLikedByUserSpec(userId));
|
||||||
int friendsCounter = await userFriendsRepository.CountAsync(new GetFriendsByUserIdSpec(userId));
|
int friendsCounter = await userFriendsRepository.CountAsync(new GetFriendsByUserIdSpec(userId));
|
||||||
int friendsRequestsCounter = await userFriendsRepository.CountAsync(new GetFriendRequestSpec(userId));
|
int friendsRequestsCounter = await userFriendsRepository.CountAsync(new GetFriendRequestSpec(userId));
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using Amazon.S3;
|
||||||
|
using Amazon.S3.Model;
|
||||||
|
|
||||||
|
namespace BeReadyBackend.Services;
|
||||||
|
|
||||||
|
public class StorageService(IAmazonS3 amazonS3, IConfiguration config)
|
||||||
|
{
|
||||||
|
private readonly string _bucket = config["RustFs:BucketName"]!;
|
||||||
|
private readonly string _url = config["RustFs:ServiceUrl"]!;
|
||||||
|
|
||||||
|
public async Task<string> UploadFile(IFormFile file, string path, CancellationToken ct)
|
||||||
|
{
|
||||||
|
if (file.Length == 0) throw new Exception("Fichier vide");
|
||||||
|
|
||||||
|
string key = $"{path}/{Guid.NewGuid()}";
|
||||||
|
|
||||||
|
using MemoryStream memoryStream = new();
|
||||||
|
await file.CopyToAsync(memoryStream, ct);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
PutObjectRequest uploadRequest = new()
|
||||||
|
{
|
||||||
|
BucketName = _bucket,
|
||||||
|
ContentType = file.ContentType,
|
||||||
|
InputStream = memoryStream,
|
||||||
|
Key = key,
|
||||||
|
};
|
||||||
|
|
||||||
|
await amazonS3.PutObjectAsync(uploadRequest, ct);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? GetUrl(string key)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(key) ? null : $"{_url}/{_bucket}/{key}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using Ardalis.Specification;
|
||||||
|
using BeReadyBackend.Models;
|
||||||
|
|
||||||
|
namespace BeReadyBackend.Specifications.RandomChallenges;
|
||||||
|
|
||||||
|
public class GetUserRandomChallengeByIdSpec : Specification<UserRandomChallenge>
|
||||||
|
{
|
||||||
|
public GetUserRandomChallengeByIdSpec(int userId)
|
||||||
|
{
|
||||||
|
Query
|
||||||
|
.Include(x => x.RandomChallenge)
|
||||||
|
.Where(x => x.UserId == userId && x.Proof != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using Ardalis.Specification;
|
|
||||||
using BeReadyBackend.Models;
|
|
||||||
|
|
||||||
namespace BeReadyBackend.Specifications.Users;
|
|
||||||
|
|
||||||
public class GetProofOrChallengeByUserIdSpec : SingleResultSpecification<User>
|
|
||||||
{
|
|
||||||
public GetProofOrChallengeByUserIdSpec(int userId)
|
|
||||||
{
|
|
||||||
Query
|
|
||||||
.Include(x => x.UserRandomChallenges!)
|
|
||||||
.ThenInclude(x => x.RandomChallenge)
|
|
||||||
.Where(x => x.Id == userId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using Ardalis.Specification;
|
||||||
|
using BeReadyBackend.Models;
|
||||||
|
|
||||||
|
namespace BeReadyBackend.Specifications.Users;
|
||||||
|
|
||||||
|
public class GetUserProofByUserIdSpec : Specification<UserRandomChallenge>
|
||||||
|
{
|
||||||
|
public GetUserProofByUserIdSpec(int userId)
|
||||||
|
{
|
||||||
|
Query
|
||||||
|
.Where(x => x.UserId == userId && x.Proof != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,9 +43,8 @@ public class CreateUserDtoValidator : Validator<CreateUserDto>
|
|||||||
RuleFor(x => x.Password)
|
RuleFor(x => x.Password)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("Password is required")
|
.WithMessage("Password is required")
|
||||||
.MaximumLength(60)
|
|
||||||
.WithMessage("Password cannot exceed 60 characters")
|
|
||||||
.MinimumLength(12)
|
.MinimumLength(12)
|
||||||
.WithMessage("Password must exceed 12 characters");
|
.WithMessage("Password must exceed 12 characters")
|
||||||
|
.Matches(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*?[#?_!@$%^&*-])");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,5 +4,11 @@
|
|||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"RustFS": {
|
||||||
|
"ServiceUrl": "https://stockage.sanchezvende.fr",
|
||||||
|
"AccessKey": "Admin_Beready_Exam2026",
|
||||||
|
"SecretKey": "4dm1n-Pr0j_2026-B3r34d7",
|
||||||
|
"BucketName": "images"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user