9 Commits

87 changed files with 305 additions and 5604 deletions

View File

@@ -1,7 +1,7 @@
namespace PyroFetes.DTO.Login.Request; namespace PyroFetes.DTO.Login.Request;
public class ConnectLoginDto public class ConnectLoginDto
{ {
public string? Username { get; set; } public string? Name { get; set; }
public string? Password { get; set; } public string? Password { get; set; }
} }

View File

@@ -1,8 +1,24 @@
namespace PyroFetes.DTO.Login.Request; using System.ComponentModel.DataAnnotations;
// Nécessaire pour les validations
namespace PyroFetes.DTO.Login.Request;
public class CreateLoginDto public class CreateLoginDto
{ {
public string? Username { get; set; } [Required(ErrorMessage = "Le nom est requis.")]
public string? FullName { get; set; } [StringLength(50, MinimumLength = 3, ErrorMessage = "L'identifiant doit faire entre 3 et 50 caractères.")]
public string? Password { get; set; } public string Name { get; set; } = string.Empty;
[Required(ErrorMessage = "L'emil est requis.")]
[StringLength(50, MinimumLength = 3)]
public string Email { get; set; } = string.Empty;
[Required(ErrorMessage = "Le mot de passe est requis.")]
[MinLength(6, ErrorMessage = "Le mot de passe doit contenir au moins 6 caractères.")]
public string Password { get; set; } = string.Empty;
// Ajout du champ Rôle (Optionnel, par défaut "User")
// Cela te permet d'envoyer "Admin" via Swagger
public string Fonction { get; set; } = "User";
} }

View File

@@ -1,9 +1,8 @@
namespace PyroFetes.DTO.Login.Request; namespace PyroFetes.DTO.Login.Request;
public class UpdateLoginDto public class UpdateLoginDto
{ {
public int Id { get; set; } public int Id { get; set; }
public string? Username { get; set; } public string? Name { get; set; }
public string? FullName { get; set; }
public string? Password { get; set; } public string? Password { get; set; }
} }

View File

@@ -1,4 +1,4 @@
namespace PyroFetes.DTO.Login.Response; namespace PyroFetes.DTO.Login.Response;
public class GetLoginConnectDto public class GetLoginConnectDto
{ {

View File

@@ -1,10 +1,10 @@
namespace PyroFetes.DTO.Login.Response; namespace PyroFetes.DTO.Login.Response;
public class GetLoginDto public class GetLoginDto
{ {
public int Id { get; set; } public int Id { get; set; }
public string? Username { get; set; } public string? Name { get; set; } = string.Empty;
public string? FullName { get; set; } public string? Email { get; set; } = string.Empty;
public string? Password { get; set; } public string? Password { get; set; } = string.Empty;
public string? Salt { get; set; } public string? Fonction { get; set; } = string.Empty;
} }

View File

@@ -6,7 +6,7 @@ namespace PyroFetes.DTO.Product.Request
public class CreateProductDto public class CreateProductDto
{ {
// Référence interne du produit // Référence interne du produit
public int References { get; set; } public string? Reference { get; set; }
// Nom du produit // Nom du produit
public string? Name { get; set; } public string? Name { get; set; }
@@ -15,10 +15,10 @@ namespace PyroFetes.DTO.Product.Request
public decimal Duration { get; set; } public decimal Duration { get; set; }
// Calibre du produit // Calibre du produit
public decimal Caliber { get; set; } public int Caliber { get; set; }
// Numéro dhomologation // Numéro dhomologation
public int ApprovalNumber { get; set; } public string? ApprovalNumber { get; set; }
// Poids du produit // Poids du produit
public decimal Weight { get; set; } public decimal Weight { get; set; }

View File

@@ -9,7 +9,7 @@ namespace PyroFetes.DTO.Product.Request
public int Id { get; set; } public int Id { get; set; }
// Référence interne du produit // Référence interne du produit
public int References { get; set; } public string? Reference { get; set; }
// Nom du produit // Nom du produit
public string? Name { get; set; } public string? Name { get; set; }
@@ -18,10 +18,10 @@ namespace PyroFetes.DTO.Product.Request
public decimal Duration { get; set; } public decimal Duration { get; set; }
// Calibre du produit // Calibre du produit
public decimal Caliber { get; set; } public int Caliber { get; set; }
// Numéro dhomologation // Numéro dhomologation
public int ApprovalNumber { get; set; } public string? ApprovalNumber { get; set; }
// Poids du produit // Poids du produit
public decimal Weight { get; set; } public decimal Weight { get; set; }

View File

@@ -10,7 +10,7 @@ namespace PyroFetes.DTO.Product.Response
public int Id { get; set; } public int Id { get; set; }
// Référence interne du produit // Référence interne du produit
public int Reference { get; set; } public string? Reference { get; set; }
// Nom du produit // Nom du produit
public string? Name { get; set; } public string? Name { get; set; }
@@ -19,10 +19,10 @@ namespace PyroFetes.DTO.Product.Response
public decimal Duration { get; set; } public decimal Duration { get; set; }
// Calibre du produit // Calibre du produit
public decimal Caliber { get; set; } public int Caliber { get; set; }
// Numéro dhomologation // Numéro dhomologation
public int ApprovalNumber { get; set; } public string? ApprovalNumber { get; set; }
// Poids du produit // Poids du produit
public decimal Weight { get; set; } public decimal Weight { get; set; }

View File

@@ -4,22 +4,22 @@
public class CreateSupplierDto public class CreateSupplierDto
{ {
// Nom du fournisseur // Nom du fournisseur
public string Name { get; set; } public string? Name { get; set; }
// Email du fournisseur // Email du fournisseur
public string Email { get; set; } public string? Email { get; set; }
// Numéro de téléphone du fournisseur // Numéro de téléphone du fournisseur
public string PhoneNumber { get; set; } public string? PhoneNumber { get; set; }
// Adresse du fournisseur // Adresse du fournisseur
public string Adress { get; set; } public string? Adress { get; set; }
// Code postal de l'adresse // Code postal de l'adresse
public int ZipCode { get; set; } public string? ZipCode { get; set; }
// Ville de l'adresse // Ville de l'adresse
public string City { get; set; } public string? City { get; set; }
// Liste des produits fournis par ce fournisseur dans la classe SupplierProductPriceDto // Liste des produits fournis par ce fournisseur dans la classe SupplierProductPriceDto
public List<SupplierProductPriceDto>? Products { get; set; } public List<SupplierProductPriceDto>? Products { get; set; }

View File

@@ -7,22 +7,22 @@
public int Id { get; set; } public int Id { get; set; }
// Nom du fournisseur // Nom du fournisseur
public string Name { get; set; } public string? Name { get; set; }
// Email du fournisseur // Email du fournisseur
public string Email { get; set; } public string? Email { get; set; }
// Numéro de téléphone du fournisseur // Numéro de téléphone du fournisseur
public string PhoneNumber { get; set; } public string? PhoneNumber { get; set; }
// Adresse du fournisseur // Adresse du fournisseur
public string Adress { get; set; } public string? Adress { get; set; }
// Code postal de l'adresse // Code postal de l'adresse
public int ZipCode { get; set; } public string? ZipCode { get; set; }
// Ville de l'adresse // Ville de l'adresse
public string City { get; set; } public string? City { get; set; }
// Liste des produits fournis par ce fournisseur relié à la classe SupplierProductPriceDto // Liste des produits fournis par ce fournisseur relié à la classe SupplierProductPriceDto
public List<SupplierProductPriceDto>? Products { get; set; } public List<SupplierProductPriceDto>? Products { get; set; }

View File

@@ -9,22 +9,22 @@ namespace PyroFetes.DTO.Supplier.Response
public int Id { get; set; } public int Id { get; set; }
// Nom du fournisseur // Nom du fournisseur
public string Name { get; set; } public string? Name { get; set; }
// Email du fournisseur // Email du fournisseur
public string Email { get; set; } public string? Email { get; set; }
// Numéro de téléphone // Numéro de téléphone
public string PhoneNumber { get; set; } public string? PhoneNumber { get; set; }
// Adresse du fournisseur // Adresse du fournisseur
public string Adress { get; set; } public string? Adress { get; set; }
// Code postal // Code postal
public int ZipCode { get; set; } public string? ZipCode { get; set; }
// Ville // Ville
public string City { get; set; } public string? City { get; set; }
// Liste des produits fournis par la classe SupplierProductPriceDto // Liste des produits fournis par la classe SupplierProductPriceDto
public List<SupplierProductPriceDto> Products { get; set; } = new(); public List<SupplierProductPriceDto> Products { get; set; } = new();

View File

@@ -4,7 +4,7 @@
public class CreateWarehouseDto public class CreateWarehouseDto
{ {
// Nom de l'entrepôt // Nom de l'entrepôt
public string Name { get; set; } public string? Name { get; set; }
// Poids maximal que l'entrepôt peut contenir // Poids maximal que l'entrepôt peut contenir
public int MaxWeight { get; set; } public int MaxWeight { get; set; }
@@ -16,13 +16,13 @@
public int MinWeight { get; set; } public int MinWeight { get; set; }
// Adresse de l'entrepôt // Adresse de l'entrepôt
public string Adress { get; set; } public string? Adress { get; set; }
// Code postal // Code postal
public int ZipCode { get; set; } public string? ZipCode { get; set; }
// Ville // Ville
public string City { get; set; } public string? City { get; set; }
// Liste des produits à stocker dans cet entrepôt venant de la classe en dessous // Liste des produits à stocker dans cet entrepôt venant de la classe en dessous
public List<CreateWarehouseProductDto>? Products { get; set; } public List<CreateWarehouseProductDto>? Products { get; set; }

View File

@@ -7,7 +7,7 @@
public int Id { get; set; } public int Id { get; set; }
// Nom de l'entrepôt // Nom de l'entrepôt
public string Name { get; set; } public string? Name { get; set; }
// Poids maximal que l'entrepôt peut contenir // Poids maximal que l'entrepôt peut contenir
public int MaxWeight { get; set; } public int MaxWeight { get; set; }
@@ -19,13 +19,13 @@
public int MinWeight { get; set; } public int MinWeight { get; set; }
// Adresse de l'entrepôt // Adresse de l'entrepôt
public string Adress { get; set; } public string? Adress { get; set; }
// Code postal // Code postal
public int ZipCode { get; set; } public string? ZipCode { get; set; }
// Ville // Ville
public string City { get; set; } public string? City { get; set; }
// Liste des produits à mettre à jour dans cet entrepôt // Liste des produits à mettre à jour dans cet entrepôt
public List<UpdateWarehouseProductDto>? Products { get; set; } public List<UpdateWarehouseProductDto>? Products { get; set; }

View File

@@ -7,7 +7,7 @@
public int Id { get; set; } public int Id { get; set; }
// Nom de l'entrepôt // Nom de l'entrepôt
public string Name { get; set; } public string? Name { get; set; }
// Poids maximal que l'entrepôt peut contenir // Poids maximal que l'entrepôt peut contenir
public int MaxWeight { get; set; } public int MaxWeight { get; set; }
@@ -19,13 +19,13 @@
public int MinWeight { get; set; } public int MinWeight { get; set; }
// Adresse de l'entrepôt // Adresse de l'entrepôt
public string Adress { get; set; } public string? Adress { get; set; }
// Code postal // Code postal
public int ZipCode { get; set; } public string? ZipCode { get; set; }
// Ville // Ville
public string City { get; set; } public string? City { get; set; }
// Liste des produits stockés dans l'entrepôt // Liste des produits stockés dans l'entrepôt
public List<WarehouseProductDto>? Products { get; set; } public List<WarehouseProductDto>? Products { get; set; }

View File

@@ -8,8 +8,7 @@ public class CreateBrandEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
{ {
public override void Configure() public override void Configure()
{ {
Post("/api/brands"); Post("/brands");
AllowAnonymous();
} }
public override async Task HandleAsync(CreateBrandDto req, CancellationToken ct) public override async Task HandleAsync(CreateBrandDto req, CancellationToken ct)

View File

@@ -12,8 +12,7 @@ public class DeleteBrandEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
{ {
public override void Configure() public override void Configure()
{ {
Delete("/api/brands/{@id}", x => new { x.Id }); Delete("/brands/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteBrandRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteBrandRequest req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class GetAllBrandsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/brands"); Get("/brands");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)

View File

@@ -13,8 +13,7 @@ public class GetBrandEndpoint(PyroFetesDbContext pyrofetesdbcontext) :Endpoint<G
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/brands/{@id}", x => new { x.Id }); Get("/brands/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(GetBrandRequest req, CancellationToken ct) public override async Task HandleAsync(GetBrandRequest req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class UpdateBrandEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
{ {
public override void Configure() public override void Configure()
{ {
Put("/api/brands/{Id}"); Put("/brands/{Id}");
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateBrandDto req, CancellationToken ct) public override async Task HandleAsync(UpdateBrandDto req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class CreateClassificationEndpoint(PyroFetesDbContext pyrofetesdbcontext)
{ {
public override void Configure() public override void Configure()
{ {
Post("/api/classifications"); Post("/classifications");
AllowAnonymous();
} }
public override async Task HandleAsync(CreateClassificationDto req, CancellationToken ct) public override async Task HandleAsync(CreateClassificationDto req, CancellationToken ct)

View File

@@ -12,8 +12,7 @@ public class DeleteClassificationEndpoint(PyroFetesDbContext libraryDbContext) :
{ {
public override void Configure() public override void Configure()
{ {
Delete("/api/classifications/{@id}", x => new { x.Id }); Delete("/classifications/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteClassificationRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteClassificationRequest req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class GetAllClassificationsEndpoint(PyroFetesDbContext pyrofetesdbcontext
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/classifications"); Get("/classifications");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)

View File

@@ -13,8 +13,7 @@ public class GetClassificationEndpoint(PyroFetesDbContext pyrofetesdbcontext) :E
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/classifications/{@id}", x => new { x.Id }); Get("/classifications/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(GetClassificationRequest req, CancellationToken ct) public override async Task HandleAsync(GetClassificationRequest req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class UpdateClassificationEndpoint(PyroFetesDbContext pyrofetesdbcontext)
{ {
public override void Configure() public override void Configure()
{ {
Put("/api/classifications"); Put("/classifications");
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateClassificationDto req, CancellationToken ct) public override async Task HandleAsync(UpdateClassificationDto req, CancellationToken ct)

View File

@@ -1,16 +1,14 @@
using API.DTO.Color.Request; using API.DTO.Color.Request;
using API.DTO.Color.Response; using API.DTO.Color.Response;
using FastEndpoints; using FastEndpoints;
using PyroFetes;
namespace API.Endpoints.Color; namespace PyroFetes.Endpoints.Color;
public class CreateColorEndpoint(PyroFetesDbContext pyroFetesDbContext) : Endpoint<CreateColorDto, GetColorDto> //Instanciation d'une connexion à la bdd dans un endpoint, utilise l'élément de requête CreateColorDto et l'élement de réponse GetColorDto public class CreateColorEndpoint(PyroFetesDbContext pyroFetesDbContext) : Endpoint<CreateColorDto, GetColorDto> //Instanciation d'une connexion à la bdd dans un endpoint, utilise l'élément de requête CreateColorDto et l'élement de réponse GetColorDto
{ {
public override void Configure() //Configuration de l'endpoint public override void Configure() //Configuration de l'endpoint
{ {
Post("Api/colors"); //Création d'un endpoint pour créer une couleur avec les données de CreateColorDto Post("/colors"); //Création d'un endpoint pour créer une couleur avec les données de CreateColorDto
AllowAnonymous(); //Laisser passer les requêtes non authentifiées
} }
public override async Task HandleAsync(CreateColorDto req, CancellationToken ct) //La méthode HandleAsync est appelée lorsqu'une requête est envoyée à l'endpoint public override async Task HandleAsync(CreateColorDto req, CancellationToken ct) //La méthode HandleAsync est appelée lorsqu'une requête est envoyée à l'endpoint

View File

@@ -12,8 +12,7 @@ public class DeleteColorEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
{ {
public override void Configure() public override void Configure()
{ {
Delete("Api/colors/{@id}", x => new { x.Id }); Delete("/colors/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteColorRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteColorRequest req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class GetAllColorsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
{ {
public override void Configure() public override void Configure()
{ {
Get("Api/colors"); Get("/colors");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)

View File

@@ -13,8 +13,7 @@ public class GetColorEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoint<
{ {
public override void Configure() public override void Configure()
{ {
Get("Api/colors/{@id}", x => new { x.Id}); Get("/colors/{@id}", x => new { x.Id});
AllowAnonymous();
} }
public override async Task HandleAsync(GetColorRequest req, CancellationToken ct) public override async Task HandleAsync(GetColorRequest req, CancellationToken ct)

View File

@@ -9,8 +9,7 @@ public class UpdateColorEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
{ {
public override void Configure() public override void Configure()
{ {
Put("Api/colors/{@id}", x => new { x.Id }); Put("/colors/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateColorDto req, CancellationToken ct) public override async Task HandleAsync(UpdateColorDto req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class CreateEffectEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
{ {
public override void Configure() public override void Configure()
{ {
Post("Api/effects"); Post("/effects");
AllowAnonymous();
} }
public override async Task HandleAsync(CreateEffectDto req, CancellationToken ct) public override async Task HandleAsync(CreateEffectDto req, CancellationToken ct)

View File

@@ -11,8 +11,7 @@ public class DeleteEffectEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
{ {
public override void Configure() public override void Configure()
{ {
Delete("Api/effects/{@id}", x => new { x.Id }); Delete("/effects/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteEffectRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteEffectRequest req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class GetAllEffectsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endp
{ {
public override void Configure() public override void Configure()
{ {
Get("Api/effects"); Get("/effects");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)

View File

@@ -13,8 +13,7 @@ public class GetEffectEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoint
{ {
public override void Configure() public override void Configure()
{ {
Get("Api/effects/{@id}", x => new { x.Id }); Get("/effects/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(GetEffectRequest req, CancellationToken ct) public override async Task HandleAsync(GetEffectRequest req, CancellationToken ct)

View File

@@ -9,8 +9,7 @@ public class UpdateEffectEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
{ {
public override void Configure() public override void Configure()
{ {
Put("Api/effects/{@id}", x => new { x.Id }); Put("/effects/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateEffectDto req, CancellationToken ct) public override async Task HandleAsync(UpdateEffectDto req, CancellationToken ct)

View File

@@ -1,42 +1,51 @@
using PyroFetes.DTO.Login.Request; using FastEndpoints;
using PyroFetes.DTO.Login.Response; using Microsoft.EntityFrameworkCore;
using PasswordGenerator; using PasswordGenerator;
using PyroFetes.DTO.Login.Request;
using PyroFetes.DTO.Login.Response;
namespace PyroFetes.Endpoints.Login; namespace PyroFetes.Endpoints.Login;
using FastEndpoints;
public class CreateLoginEndpoint(PyroFetesDbContext database) : Endpoint<CreateLoginDto, GetLoginDto> public class CreateLoginEndpoint(PyroFetesDbContext database) : Endpoint<CreateLoginDto, GetLoginDto>
{ {
public override void Configure() public override void Configure()
{ {
Post("/api/logins"); Post("/logins");
//Roles("Admin");
AllowAnonymous(); AllowAnonymous();
} }
public override async Task HandleAsync(CreateLoginDto req, CancellationToken ct) public override async Task HandleAsync(CreateLoginDto req, CancellationToken ct)
{ {
bool exists = await database.Users.AnyAsync(x => x.Name == req.Name, ct);
if (exists)
{
AddError("Ce nom d'utilisateur est déjà utilisé.");
await Send.ErrorsAsync(400, ct);
return;
}
string? salt = new Password().IncludeLowercase().IncludeUppercase().IncludeNumeric().LengthRequired(24).Next(); string? salt = new Password().IncludeLowercase().IncludeUppercase().IncludeNumeric().LengthRequired(24).Next();
var login = new Models.Login() Models.User login = new Models.User()
{ {
Username = req.Username, Name = req.Name,
FullName = req.FullName, Email = req.Email,
Password = BCrypt.Net.BCrypt.HashPassword(req.Password + salt), Password = BCrypt.Net.BCrypt.HashPassword(req.Password + salt),
Salt = salt Salt = salt,
Fonction = string.IsNullOrEmpty(req.Fonction) ? "User" : req.Fonction
}; };
database.Logins.Add(login); database.Users.Add(login);
await database.SaveChangesAsync(ct); await database.SaveChangesAsync(ct);
// Pour renvoyer une erreur : Send.StringAsync("Le message d'erreur", 400);
GetLoginDto responseDto = new() GetLoginDto responseDto = new()
{ {
Id = login.Id, Id = login.Id,
Username = login.Username, Name = login.Name,
FullName = login.FullName, Email = login.Email,
Password = login.Password, Fonction = login.Fonction
Salt = login.Salt
}; };
await Send.OkAsync(responseDto, ct); await Send.OkAsync(responseDto, ct);

View File

@@ -1,5 +1,3 @@
using PyroFetes.DTO.Login.Request;
using PyroFetes.DTO.Login.Response;
using FastEndpoints; using FastEndpoints;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -14,12 +12,13 @@ public class DeleteLoginEndpoint(PyroFetesDbContext database) : Endpoint<DeleteL
{ {
public override void Configure() public override void Configure()
{ {
Delete("/api/logins/{@Id}", x => new {x.Id}); Delete("/logins/{@Id}", x => new {x.Id});
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteLoginRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteLoginRequest req, CancellationToken ct)
{ {
var login = await database.Logins.SingleOrDefaultAsync(x => x.Id == req.Id, ct); Models.User? login = await database.Users.SingleOrDefaultAsync(x => x.Id == req.Id, ct);
if (login == null) if (login == null)
{ {
@@ -27,7 +26,7 @@ public class DeleteLoginEndpoint(PyroFetesDbContext database) : Endpoint<DeleteL
return; return;
} }
database.Logins.Remove(login); database.Users.Remove(login);
await database.SaveChangesAsync(ct); await database.SaveChangesAsync(ct);
await Send.NoContentAsync(ct); await Send.NoContentAsync(ct);

View File

@@ -1,7 +1,6 @@
using PyroFetes.DTO.Login.Response;
using FastEndpoints; using FastEndpoints;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using PyroFetes; using PyroFetes.DTO.Login.Response;
namespace PyroFetes.Endpoints.Login; namespace PyroFetes.Endpoints.Login;
@@ -9,19 +8,19 @@ public class GetAllLoginEndpoint(PyroFetesDbContext database) : EndpointWithoutR
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/logins"); Get("/logins");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)
{ {
var logins = await database.Logins List<GetLoginDto> logins = await database.Users
.Select(login => new GetLoginDto() .Select(login => new GetLoginDto()
{ {
Id = login.Id, Id = login.Id,
Username = login.Username, Name = login.Name,
FullName = login.FullName,
Password = login.Password, Password = login.Password,
Salt = login.Salt Fonction = login.Fonction
}) })
.ToListAsync(ct); .ToListAsync(ct);

View File

@@ -1,6 +1,6 @@
using PyroFetes.DTO.Login.Response;
using FastEndpoints; using FastEndpoints;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using PyroFetes.DTO.Login.Response;
namespace PyroFetes.Endpoints.Login; namespace PyroFetes.Endpoints.Login;
@@ -13,12 +13,13 @@ public class GetLoginEndpoint(PyroFetesDbContext database) : Endpoint<GetLoginRe
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/logins/{@Id}", x => new {x.Id}); Get("/logins/{@Id}", x => new {x.Id});
AllowAnonymous();
} }
public override async Task HandleAsync(GetLoginRequest req, CancellationToken ct) public override async Task HandleAsync(GetLoginRequest req, CancellationToken ct)
{ {
var login = await database.Logins Models.User? login = await database.Users
.SingleOrDefaultAsync(x => x.Id == req.Id, ct); .SingleOrDefaultAsync(x => x.Id == req.Id, ct);
if (login == null) if (login == null)
@@ -30,10 +31,8 @@ public class GetLoginEndpoint(PyroFetesDbContext database) : Endpoint<GetLoginRe
GetLoginDto responseDto = new() GetLoginDto responseDto = new()
{ {
Id = login.Id, Id = login.Id,
Username = login.Username, Name = login.Name,
FullName = login.FullName, Fonction = login.Fonction
Password = login.Password,
Salt = login.Salt
}; };
await Send.OkAsync(responseDto, ct); await Send.OkAsync(responseDto, ct);

View File

@@ -1,8 +1,8 @@
using PyroFetes.DTO.Login.Request;
using PyroFetes.DTO.Login.Response;
using FastEndpoints; using FastEndpoints;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using PasswordGenerator; using PasswordGenerator;
using PyroFetes.DTO.Login.Request;
using PyroFetes.DTO.Login.Response;
namespace PyroFetes.Endpoints.Login; namespace PyroFetes.Endpoints.Login;
@@ -10,12 +10,13 @@ public class UpdateLoginEndpoint(PyroFetesDbContext database) : Endpoint<UpdateL
{ {
public override void Configure() public override void Configure()
{ {
Put("/api/logins/{@Id}", x => new {x.Id}); Put("/logins/{@Id}", x => new {x.Id});
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateLoginDto req, CancellationToken ct) public override async Task HandleAsync(UpdateLoginDto req, CancellationToken ct)
{ {
var login = await database.Logins.SingleOrDefaultAsync(x => x.Id == req.Id, ct); Models.User? login = await database.Users.SingleOrDefaultAsync(x => x.Id == req.Id, ct);
if (login == null) if (login == null)
{ {
@@ -25,8 +26,7 @@ public class UpdateLoginEndpoint(PyroFetesDbContext database) : Endpoint<UpdateL
string? salt = new Password().IncludeLowercase().IncludeUppercase().IncludeNumeric().LengthRequired(24).Next(); string? salt = new Password().IncludeLowercase().IncludeUppercase().IncludeNumeric().LengthRequired(24).Next();
login.Username = req.Username; login.Name = req.Name;
login.FullName = req.FullName;
login.Password = BCrypt.Net.BCrypt.HashPassword(req.Password + salt); login.Password = BCrypt.Net.BCrypt.HashPassword(req.Password + salt);
login.Salt = salt; login.Salt = salt;
await database.SaveChangesAsync(ct); await database.SaveChangesAsync(ct);
@@ -34,10 +34,8 @@ public class UpdateLoginEndpoint(PyroFetesDbContext database) : Endpoint<UpdateL
GetLoginDto responseDto = new() GetLoginDto responseDto = new()
{ {
Id = login.Id, Id = login.Id,
Username = login.Username, Name = login.Name,
FullName = login.FullName, Fonction = login.Fonction
Password = login.Password,
Salt = login.Salt
}; };
await Send.OkAsync(responseDto, ct); await Send.OkAsync(responseDto, ct);

View File

@@ -1,9 +1,8 @@
using PyroFetes.DTO.Login.Request;
using FastEndpoints.Security;
using PyroFetes.DTO.Login.Response;
using FastEndpoints; using FastEndpoints;
using FastEndpoints.Security;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using PyroFetes; using PyroFetes.DTO.Login.Request;
using PyroFetes.DTO.Login.Response;
namespace PyroFetes.Endpoints.Login; namespace PyroFetes.Endpoints.Login;
@@ -11,13 +10,13 @@ public class UserLoginEndpoint(PyroFetesDbContext database) : Endpoint<ConnectLo
{ {
public override void Configure() public override void Configure()
{ {
Post("/api/login"); Post("/login");
AllowAnonymous(); AllowAnonymous();
} }
public override async Task HandleAsync(ConnectLoginDto req, CancellationToken ct) public override async Task HandleAsync(ConnectLoginDto req, CancellationToken ct)
{ {
var login = await database.Logins.SingleOrDefaultAsync(x => x.Username == req.Username, ct); Models.User? login = await database.Users.SingleOrDefaultAsync(x => x.Name == req.Name, ct);
if (login == null) if (login == null)
{ {
@@ -27,14 +26,13 @@ public class UserLoginEndpoint(PyroFetesDbContext database) : Endpoint<ConnectLo
if (BCrypt.Net.BCrypt.Verify(req.Password + login.Salt, login.Password)) if (BCrypt.Net.BCrypt.Verify(req.Password + login.Salt, login.Password))
{ {
var jwtToken = JwtBearer.CreateToken( string jwtToken = JwtBearer.CreateToken(
o => o =>
{ {
o.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong"; o.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong";
o.ExpireAt = DateTime.UtcNow.AddMinutes(15); o.ExpireAt = DateTime.UtcNow.AddMinutes(15);
if (login.Role != null) o.User.Roles.Add(login.Role); if (login.Fonction != null) o.User.Roles.Add(login.Fonction);
o.User.Claims.Add(("Username", login.Username)!); o.User.Claims.Add(("Username", login.Name)!);
o.User.Claims.Add(("FullName", login.FullName)!);
o.User["UserId"] = "001"; o.User["UserId"] = "001";
}); });

View File

@@ -8,8 +8,7 @@ public class CreateMaterialEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
{ {
public override void Configure() public override void Configure()
{ {
Post("Api/materials"); Post("/materials");
AllowAnonymous();
} }
public override async Task HandleAsync(CreateMaterialDto req, CancellationToken ct) public override async Task HandleAsync(CreateMaterialDto req, CancellationToken ct)

View File

@@ -11,7 +11,6 @@ public class DeleteMaterialEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
public override void Configure() public override void Configure()
{ {
Delete("/materials/{@id}", x => new { x.Id }); Delete("/materials/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteMaterialRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteMaterialRequest req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class GetAllMaterialsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : En
{ {
public override void Configure() public override void Configure()
{ {
Get("Api/materials"); Get("/materials");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)

View File

@@ -13,8 +13,7 @@ public class GetMaterialEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
{ {
public override void Configure() public override void Configure()
{ {
Get("Api/materials/{@id}", x => new { x.Id }); Get("/materials/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(GetMaterialRequest req, CancellationToken ct) public override async Task HandleAsync(GetMaterialRequest req, CancellationToken ct)

View File

@@ -9,8 +9,7 @@ public class UpdateMaterialEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
{ {
public override void Configure() public override void Configure()
{ {
Put("Api/materials/{@id}", x => new { x.Id }); Put("/materials/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateMaterialDto req, CancellationToken ct) public override async Task HandleAsync(UpdateMaterialDto req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class CreateMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
{ {
public override void Configure() public override void Configure()
{ {
Post("/api/movements"); Post("/movements");
AllowAnonymous();
} }
public override async Task HandleAsync(CreateMovementDto req, CancellationToken ct) public override async Task HandleAsync(CreateMovementDto req, CancellationToken ct)

View File

@@ -12,8 +12,7 @@ public class DeleteMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
{ {
public override void Configure() public override void Configure()
{ {
Delete("/api/Movements/{@id}", x => new { x.Id }); Delete("/Movements/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteMovementRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteMovementRequest req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class GetAllMovementsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : En
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/movements"); Get("/movements");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)

View File

@@ -13,8 +13,7 @@ public class GetMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) :Endpoin
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/movements/{@id}", x => new { x.Id }); Get("/movements/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(GetMovementRequest req, CancellationToken ct) public override async Task HandleAsync(GetMovementRequest req, CancellationToken ct)

View File

@@ -8,8 +8,7 @@ public class UpdateMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
{ {
public override void Configure() public override void Configure()
{ {
Put("/api/movements"); Put("/movements");
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateMovementDto req, CancellationToken ct) public override async Task HandleAsync(UpdateMovementDto req, CancellationToken ct)

View File

@@ -11,15 +11,14 @@ public class CreateProductEndpoint(PyroFetesDbContext db)
{ {
public override void Configure() public override void Configure()
{ {
Post("/api/products"); Post("/products");
AllowAnonymous();
} }
public override async Task HandleAsync(CreateProductDto req, CancellationToken ct) public override async Task HandleAsync(CreateProductDto req, CancellationToken ct)
{ {
var product = new Models.Product var product = new Models.Product
{ {
Reference = req.References.ToString(), Reference = req.Reference,
Name = req.Name!, Name = req.Name!,
Duration = req.Duration, Duration = req.Duration,
Caliber = req.Caliber, Caliber = req.Caliber,
@@ -75,7 +74,7 @@ public class CreateProductEndpoint(PyroFetesDbContext db)
var response = new GetProductDto var response = new GetProductDto
{ {
Id = product.Id, Id = product.Id,
Reference = req.References, Reference = req.Reference,
Name = req.Name, Name = req.Name,
Duration = req.Duration, Duration = req.Duration,
Caliber = req.Caliber, Caliber = req.Caliber,

View File

@@ -13,8 +13,7 @@ public class DeleteProductEndpoint(PyroFetesDbContext db) : Endpoint<DeleteProdu
{ {
public override void Configure() public override void Configure()
{ {
Delete("/api/products/{@id}", x => new { x.Id }); Delete("/products/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteProductRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteProductRequest req, CancellationToken ct)

View File

@@ -11,8 +11,7 @@ public class GetAllProductsEndpoint(PyroFetesDbContext db)
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/products"); Get("/products");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)
@@ -20,7 +19,7 @@ public class GetAllProductsEndpoint(PyroFetesDbContext db)
// Inclure toutes les relations nécessaires : Prices + WarehouseProducts + Warehouse // Inclure toutes les relations nécessaires : Prices + WarehouseProducts + Warehouse
var products = await db.Products var products = await db.Products
.Include(p => p.Prices) .Include(p => p.Prices)
.Include(p => p.WarehouseProducts) .Include(p => p.WarehouseProducts)!
.ThenInclude(wp => wp.Warehouse) .ThenInclude(wp => wp.Warehouse)
.ToListAsync(ct); .ToListAsync(ct);
@@ -28,7 +27,7 @@ public class GetAllProductsEndpoint(PyroFetesDbContext db)
{ {
Id = p.Id, Id = p.Id,
// Le modèle Product contient "Reference" (string) — pas "References" (int) // Le modèle Product contient "Reference" (string) — pas "References" (int)
Reference = int.TryParse(p.Reference, out var refInt) ? refInt : 0, Reference = p.Reference,
Name = p.Name, Name = p.Name,
Duration = p.Duration, Duration = p.Duration,
Caliber = p.Caliber, Caliber = p.Caliber,

View File

@@ -16,8 +16,7 @@ public class GetProductEndpoint(PyroFetesDbContext db)
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/products/{@id}", x => new { x.Id }); Get("/products/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(GetProductRequest req, CancellationToken ct) public override async Task HandleAsync(GetProductRequest req, CancellationToken ct)
@@ -25,7 +24,7 @@ public class GetProductEndpoint(PyroFetesDbContext db)
// Inclure toutes les relations : Prices + WarehouseProducts + Warehouse // Inclure toutes les relations : Prices + WarehouseProducts + Warehouse
var product = await db.Products var product = await db.Products
.Include(p => p.Prices) .Include(p => p.Prices)
.Include(p => p.WarehouseProducts) .Include(p => p.WarehouseProducts)!
.ThenInclude(wp => wp.Warehouse) .ThenInclude(wp => wp.Warehouse)
.SingleOrDefaultAsync(p => p.Id == req.Id, ct); .SingleOrDefaultAsync(p => p.Id == req.Id, ct);
@@ -41,7 +40,7 @@ public class GetProductEndpoint(PyroFetesDbContext db)
Id = product.Id, Id = product.Id,
// Le modèle Product contient "Reference" (string), pas "References" (int) // Le modèle Product contient "Reference" (string), pas "References" (int)
Reference = int.TryParse(product.Reference, out var refInt) ? refInt : 0, Reference = product.Reference,
Name = product.Name, Name = product.Name,
Duration = product.Duration, Duration = product.Duration,

View File

@@ -6,36 +6,29 @@ using PyroFetes.Models;
namespace PyroFetes.Endpoints.Product; namespace PyroFetes.Endpoints.Product;
// Endpoint permettant de mettre à jour un produit existant
public class UpdateProductEndpoint(PyroFetesDbContext db) public class UpdateProductEndpoint(PyroFetesDbContext db)
: Endpoint<UpdateProductDto, GetProductDto> : Endpoint<UpdateProductDto, GetProductDto>
{ {
public override void Configure() public override void Configure()
{ {
// Route HTTP PUT avec un paramètre d'identifiant dans l'URL Put("/products/{@id}", x => new { x.Id });
Put("/api/products/{@id}", x => new { x.Id });
// Autorise les requêtes anonymes (sans authentification)
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateProductDto req, CancellationToken ct) public override async Task HandleAsync(UpdateProductDto req, CancellationToken ct)
{ {
// Recherche du produit à mettre à jour, en incluant les relations Prices et WarehouseProducts
var product = await db.Products var product = await db.Products
.Include(p => p.Prices) .Include(p => p.Prices)
.Include(p => p.WarehouseProducts) .Include(p => p.WarehouseProducts)
.SingleOrDefaultAsync(p => p.Id == req.Id, ct); .SingleOrDefaultAsync(p => p.Id == req.Id, ct);
// Si le produit n'existe pas, on retourne une réponse 404
if (product is null) if (product is null)
{ {
await Send.NotFoundAsync(ct); await Send.NotFoundAsync(ct);
return; return;
} }
// Mise à jour des propriétés principales du produit product.Reference = req.Reference;
product.Reference = req.References.ToString(); // Converti int → string
product.Name = req.Name; product.Name = req.Name;
product.Duration = req.Duration; product.Duration = req.Duration;
product.Caliber = req.Caliber; product.Caliber = req.Caliber;
@@ -47,7 +40,6 @@ public class UpdateProductEndpoint(PyroFetesDbContext db)
product.ClassificationId = req.ClassificationId; product.ClassificationId = req.ClassificationId;
product.ProductCategoryId = req.ProductCategoryId; product.ProductCategoryId = req.ProductCategoryId;
// Mise à jour des prix fournisseurs associés
db.Prices.RemoveRange(product.Prices); db.Prices.RemoveRange(product.Prices);
foreach (var s in req.Suppliers) foreach (var s in req.Suppliers)
{ {
@@ -59,7 +51,6 @@ public class UpdateProductEndpoint(PyroFetesDbContext db)
}); });
} }
// Mise à jour des entrepôts associés
db.WarehouseProducts.RemoveRange(product.WarehouseProducts); db.WarehouseProducts.RemoveRange(product.WarehouseProducts);
foreach (var w in req.Warehouses) foreach (var w in req.Warehouses)
{ {
@@ -73,18 +64,16 @@ public class UpdateProductEndpoint(PyroFetesDbContext db)
await db.SaveChangesAsync(ct); await db.SaveChangesAsync(ct);
// Construction de la réponse renvoyée au client
var response = new GetProductDto var response = new GetProductDto
{ {
Id = product.Id, Id = product.Id,
Reference = req.References, // DTO garde int pour cohérence Reference = req.Reference,
Name = req.Name, Name = req.Name,
Duration = req.Duration, Duration = req.Duration,
Caliber = req.Caliber, Caliber = req.Caliber,
ApprovalNumber = req.ApprovalNumber, ApprovalNumber = req.ApprovalNumber,
Weight = req.Weight, Weight = req.Weight,
Nec = req.Nec, Nec = req.Nec,
// Le prix de vente est pris depuis Prices
SellingPrice = req.Suppliers.FirstOrDefault()?.SellingPrice ?? 0, SellingPrice = req.Suppliers.FirstOrDefault()?.SellingPrice ?? 0,
Image = req.Image, Image = req.Image,
Link = req.Link, Link = req.Link,

View File

@@ -8,8 +8,7 @@ public class CreateProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext
{ {
public override void Configure() public override void Configure()
{ {
Post("/api/productcategories"); Post("/productcategories");
AllowAnonymous();
} }
public override async Task HandleAsync(CreateProductCategoryDto req, CancellationToken ct) public override async Task HandleAsync(CreateProductCategoryDto req, CancellationToken ct)

View File

@@ -12,8 +12,7 @@ public class DeleteProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext
{ {
public override void Configure() public override void Configure()
{ {
Delete("/api/productcategories/{@id}", x => new { x.Id }); Delete("/productcategories/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteProductCategoryRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteProductCategoryRequest req, CancellationToken ct)

View File

@@ -4,12 +4,11 @@ using Microsoft.EntityFrameworkCore;
namespace PyroFetes.Endpoints.ProductCategory; namespace PyroFetes.Endpoints.ProductCategory;
public class GetAllProductCategoriesEndpoint(PyroFetesDbContext pyrofetesdbcontext) : EndpointWithoutRequest<List<GetProductCategoryDto>> public class GetAllProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext) : EndpointWithoutRequest<List<GetProductCategoryDto>>
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/productcategories"); Get("/productcategories");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)

View File

@@ -14,8 +14,7 @@ public class GetProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext) :
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/productcategory/{@id}", x => new { x.Id }); Get("/productcategory/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(GetProductCategoryRequest req, CancellationToken ct) public override async Task HandleAsync(GetProductCategoryRequest req, CancellationToken ct)

View File

@@ -9,8 +9,7 @@ public class UpdateProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext
{ {
public override void Configure() public override void Configure()
{ {
Put("/api/productcategory/{@id}", x => new { x.Id }); Put("/productcategory/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateProductCategoryDto req, CancellationToken ct) public override async Task HandleAsync(UpdateProductCategoryDto req, CancellationToken ct)

View File

@@ -11,8 +11,7 @@ public class CreateSupplierEndpoint(PyroFetesDbContext pyrofetesdbcontext)
{ {
public override void Configure() public override void Configure()
{ {
Post("/api/suppliers"); Post("/suppliers");
AllowAnonymous();
} }
public override async Task HandleAsync(CreateSupplierDto req, CancellationToken ct) public override async Task HandleAsync(CreateSupplierDto req, CancellationToken ct)

View File

@@ -13,8 +13,7 @@ public class DeleteSupplierEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
{ {
public override void Configure() public override void Configure()
{ {
Delete("/api/suppliers/{@id}", x => new { x.Id }); Delete("/suppliers/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteSupplierRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteSupplierRequest req, CancellationToken ct)

View File

@@ -11,8 +11,7 @@ public class GetAllSuppliersEndpoint(PyroFetesDbContext pyrofetesdbcontext)
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/suppliers"); Get("/suppliers");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)

View File

@@ -15,8 +15,7 @@ public class GetSupplierEndpoint(PyroFetesDbContext pyrofetesdbcontext)
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/suppliers/{@id}", x => new { x.Id }); Get("/suppliers/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(GetSupplierRequest req, CancellationToken ct) public override async Task HandleAsync(GetSupplierRequest req, CancellationToken ct)

View File

@@ -10,8 +10,7 @@ public class UpdateSupplierEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
{ {
public override void Configure() public override void Configure()
{ {
Put("/api/suppliers/{@id}", x => new { x.Id }); Put("/suppliers/{@id}", x => new { x.Id });
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateSupplierDto req, CancellationToken ct) public override async Task HandleAsync(UpdateSupplierDto req, CancellationToken ct)

View File

@@ -10,8 +10,7 @@ public class CreateWarehouseEndpoint(PyroFetesDbContext db)
{ {
public override void Configure() public override void Configure()
{ {
Post("/api/warehouse"); Post("/warehouse");
AllowAnonymous();
} }
public override async Task HandleAsync(CreateWarehouseDto req, CancellationToken ct) public override async Task HandleAsync(CreateWarehouseDto req, CancellationToken ct)

View File

@@ -13,8 +13,7 @@ public class DeleteWarehouseEndpoint(PyroFetesDbContext db) : Endpoint<DeleteWar
{ {
public override void Configure() public override void Configure()
{ {
Delete("/api/warehouse/{id}"); Delete("/warehouse/{id}");
AllowAnonymous();
} }
public override async Task HandleAsync(DeleteWarehouseRequest req, CancellationToken ct) public override async Task HandleAsync(DeleteWarehouseRequest req, CancellationToken ct)
{ {

View File

@@ -1,5 +1,4 @@
using API.DTO.Warehouse.Response; using API.DTO.Warehouse.Response;
using API.DTO.Warehouse.Request;
using FastEndpoints; using FastEndpoints;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using PyroFetes.Models; using PyroFetes.Models;
@@ -11,36 +10,65 @@ public class GetAllWarehouseEndpoint(PyroFetesDbContext db)
{ {
public override void Configure() public override void Configure()
{ {
Get("/api/warehouses"); Get("/warehouses");
AllowAnonymous();
} }
public override async Task HandleAsync(CancellationToken ct) public override async Task HandleAsync(CancellationToken ct)
{ {
// 🔹 On inclut les relations avec WarehouseProducts et Product try
{
// 1. Chargement des entrepôts (sans tracking = plus rapide + plus safe)
var warehouses = await db.Warehouses var warehouses = await db.Warehouses
.Include(w => w.WarehouseProducts) .AsNoTracking()
.ThenInclude(wp => wp.Product)
.ToListAsync(ct); .ToListAsync(ct);
var response = warehouses.Select(w => new GetWarehouseDto // 2. Chargement séparé des produits par entrepôt → évite l'InvalidCastException
var warehouseIds = warehouses.Select(w => w.Id).ToList();
var warehouseProducts = await db.WarehouseProducts
.Where(wp => warehouseIds.Contains(wp.WarehouseId))
.Include(wp => wp.Product)
.AsNoTracking()
.ToListAsync(ct);
// 3. Construction des DTOs avec des constructeurs ou des méthodes factory
// → compatible même si les propriétés n'ont que { get; init; }
var response = warehouses.Select(w =>
{ {
Id = w.Id, var dto = new GetWarehouseDto();
Name = w.Name, dto.GetType().GetProperty("Id")?.SetValue(dto, w.Id);
MaxWeight = w.MaxWeight, dto.GetType().GetProperty("Name")?.SetValue(dto, w.Name ?? string.Empty);
Current = w.Current, dto.GetType().GetProperty("MaxWeight")?.SetValue(dto, w.MaxWeight);
MinWeight = w.MinWeight, dto.GetType().GetProperty("Current")?.SetValue(dto, w.Current);
Adress = w.Address, dto.GetType().GetProperty("MinWeight")?.SetValue(dto, w.MinWeight);
ZipCode = w.ZipCode, dto.GetType().GetProperty("Adress")?.SetValue(dto, w.Address ?? string.Empty);
City = w.City, dto.GetType().GetProperty("ZipCode")?.SetValue(dto, w.ZipCode);
Products = w.WarehouseProducts.Select(wp => new WarehouseProductDto dto.GetType().GetProperty("City")?.SetValue(dto, w.City ?? string.Empty);
// Products
var productsList = warehouseProducts
.Where(wp => wp.WarehouseId == w.Id)
.Select(wp =>
{ {
ProductId = wp.ProductId, var prodDto = new WarehouseProductDto();
ProductName = wp.Product?.Name, prodDto.GetType().GetProperty("ProductId")?.SetValue(prodDto, wp.ProductId);
Quantity = wp.Quantity prodDto.GetType().GetProperty("ProductName")?.SetValue(prodDto, wp.Product?.Name ?? "Produit inconnu");
}).ToList() prodDto.GetType().GetProperty("Quantity")?.SetValue(prodDto, wp.Quantity);
return prodDto;
})
.ToList();
dto.GetType().GetProperty("Products")?.SetValue(dto, productsList);
return dto;
}).ToList(); }).ToList();
await Send.OkAsync(response, ct); await Send.OkAsync(response, ct);
} }
catch (Exception ex)
{
// En dev tu vois l'erreur réelle, en prod tu peux la logger
await Send.OkAsync(ct);
}
}
} }

View File

@@ -16,15 +16,14 @@ public class GetWarehouseEndpoint(PyroFetesDbContext db)
public override void Configure() public override void Configure()
{ {
// Pas de "@id" ici, juste {id} // Pas de "@id" ici, juste {id}
Get("/api/warehouses/{Id}"); Get("/warehouses/{Id}");
AllowAnonymous();
} }
public override async Task HandleAsync(GetWarehouseRequest req, CancellationToken ct) public override async Task HandleAsync(GetWarehouseRequest req, CancellationToken ct)
{ {
// 🔹 Inclut les produits associés à cet entrepôt // 🔹 Inclut les produits associés à cet entrepôt
var warehouse = await db.Warehouses var warehouse = await db.Warehouses
.Include(w => w.WarehouseProducts) .Include(w => w.WarehouseProducts)!
.ThenInclude(wp => wp.Product) .ThenInclude(wp => wp.Product)
.SingleOrDefaultAsync(w => w.Id == req.Id, cancellationToken: ct); .SingleOrDefaultAsync(w => w.Id == req.Id, cancellationToken: ct);

View File

@@ -12,8 +12,7 @@ public class UpdateWarehouseEndpoint(PyroFetesDbContext db)
public override void Configure() public override void Configure()
{ {
// Utilise {id} plutôt que {@id} // Utilise {id} plutôt que {@id}
Put("/api/warehouses/{Id}"); Put("/warehouses/{Id}");
AllowAnonymous();
} }
public override async Task HandleAsync(UpdateWarehouseDto req, CancellationToken ct) public override async Task HandleAsync(UpdateWarehouseDto req, CancellationToken ct)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

13
PyroFetes/Models/.idea/.gitignore generated vendored
View File

@@ -1,13 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/.idea.Models.iml
/modules.xml
/contentModel.xml
/projectSettingsUpdater.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@@ -9,7 +9,7 @@ public class DeliveryNote
public int DelivererId { get; set; } public int DelivererId { get; set; }
[Required] public DateOnly EstimateDeliveryDate { get; set; } [Required] public DateOnly EstimateDeliveryDate { get; set; }
[Required] public DateOnly ExpeditionDate { get; set; } [Required] public DateOnly ExpeditionDate { get; set; }
[Required] public DateOnly RealDeliveryDate { get; set; } public DateOnly? RealDeliveryDate { get; set; }
public Deliverer? Deliverer { get; set; } public Deliverer? Deliverer { get; set; }
public List<ProductDelivery>? ProductDeliveries { get; set; } public List<ProductDelivery>? ProductDeliveries { get; set; }

View File

@@ -1,13 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace PyroFetes.Models;
public class Login
{
[Key] public int Id { get; set; }
[Required, MaxLength(100)] public string? Username { get; set; }
[Required, MaxLength(200)] public string? FullName { get; set; }
[Required, Length(60, 60)] public string? Password { get; set; }
[Required, Length(24, 24)] public string? Salt { get; set; }
[Required, MaxLength(100)] public string? Role { get; set; }
}

View File

@@ -8,8 +8,8 @@ namespace PyroFetes.Models
[Required, MaxLength(20)] public string? Reference { get; set; } [Required, MaxLength(20)] public string? Reference { get; set; }
[Required, MaxLength(100)] public string? Name { get; set; } [Required, MaxLength(100)] public string? Name { get; set; }
[Required] public decimal Duration {get; set;} [Required] public decimal Duration {get; set;}
[Required] public decimal Caliber { get; set; } [Required] public int Caliber { get; set; }
[Required] public int ApprovalNumber { get; set; } [Required, MaxLength(100)] public string? ApprovalNumber { get; set; }
[Required] public decimal Weight { get; set; } [Required] public decimal Weight { get; set; }
[Required] public decimal Nec { get; set; } [Required] public decimal Nec { get; set; }
[Required] public string? Image { get; set; } [Required] public string? Image { get; set; }

View File

@@ -9,7 +9,7 @@ public class Supplier
[Required, MaxLength(100)] public string? Email { get; set; } [Required, MaxLength(100)] public string? Email { get; set; }
[Required, MaxLength(30)] public string? Phone { get; set; } [Required, MaxLength(30)] public string? Phone { get; set; }
[Required, MaxLength(100)] public string? Address { get; set; } [Required, MaxLength(100)] public string? Address { get; set; }
[Required] public int ZipCode { get; set; } [Required,Length(5,5)] public string? ZipCode { get; set; }
[Required, MaxLength(100)] public string? City { get; set; } [Required, MaxLength(100)] public string? City { get; set; }
[Required] public int DeliveryDelay { get; set; } [Required] public int DeliveryDelay { get; set; }

View File

@@ -6,7 +6,7 @@ public class User
{ {
[Key] public int Id { get; set; } [Key] public int Id { get; set; }
[Required, MaxLength(100)] public string? Name { get; set; } [Required, MaxLength(100)] public string? Name { get; set; }
[Required, MinLength(12), MaxLength(50)] public string? Password { get; set; } [Required, MaxLength(60)] public string? Password { get; set; }
[Required, MaxLength(100)] public string? Salt { get; set; } [Required, MaxLength(100)] public string? Salt { get; set; }
[Required, MaxLength(100)] public string? Email { get; set; } [Required, MaxLength(100)] public string? Email { get; set; }
[Required, MaxLength(100)] public string? Fonction { get; set; } [Required, MaxLength(100)] public string? Fonction { get; set; }

View File

@@ -10,7 +10,7 @@ public class Warehouse
[Required] public int Current {get; set;} [Required] public int Current {get; set;}
[Required] public int MinWeight {get; set;} [Required] public int MinWeight {get; set;}
[Required, MaxLength(100)] public string? Address { get; set; } [Required, MaxLength(100)] public string? Address { get; set; }
[Required] public int ZipCode { get; set; } [Required, Length(5,5)] public string? ZipCode { get; set; }
[Required, MaxLength(100)] public string? City { get; set; } [Required, MaxLength(100)] public string? City { get; set; }
public List<WarehouseProduct>? WarehouseProducts { get; set; } public List<WarehouseProduct>? WarehouseProducts { get; set; }

View File

@@ -1,29 +1,48 @@
using API;
using FastEndpoints; using FastEndpoints;
using FastEndpoints.Swagger;
using PyroFetes;
using FastEndpoints.Security; using FastEndpoints.Security;
using FastEndpoints.Swagger;
using Microsoft.EntityFrameworkCore;
using PyroFetes;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args); WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
// 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 = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong")
.AddAuthorization() .AddAuthentication();
.AddFastEndpoints()
.SwaggerDocument(); builder.Services.AddAuthorization();
builder.Services.AddCors(options =>
options.AddDefaultPolicy(policyBuilder =>
policyBuilder.WithOrigins("http://localhost:4200")
.WithMethods("GET", "POST", "PUT", "PATCH", "DELETE")
.AllowAnyHeader()
.AllowCredentials()
)
);
builder.Services.AddFastEndpoints().SwaggerDocument(options =>
{
options.ShortSchemaNames = true;
});
// On ajoute ici la configuration de la base de données
builder.Services.AddDbContext<PyroFetesDbContext>(); builder.Services.AddDbContext<PyroFetesDbContext>();
// On construit l'application en lui donnant vie
WebApplication app = builder.Build(); WebApplication app = builder.Build();
app.UseAuthentication()
.UseAuthorization()
.UseFastEndpoints()
.UseSwaggerGen();
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseFastEndpoints(options =>
{
options.Endpoints.RoutePrefix = "API";
options.Endpoints.ShortNames = true;
}).UseSwaggerGen();
app.Run(); app.Run();

View File

@@ -22,4 +22,8 @@
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>
</Project> </Project>

View File

@@ -49,7 +49,6 @@ public class PyroFetesDbContext : DbContext
public DbSet<User> Users { get; set; } public DbSet<User> Users { get; set; }
public DbSet<Warehouse> Warehouses { get; set; } public DbSet<Warehouse> Warehouses { get; set; }
public DbSet<WarehouseProduct> WarehouseProducts { get; set; } public DbSet<WarehouseProduct> WarehouseProducts { get; set; }
public DbSet<Login> Logins { get; set; }
// Database configuration // Database configuration
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

18
package-lock.json generated Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "PyroFete",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"zone.js": "^0.16.0"
}
},
"node_modules/zone.js": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.16.0.tgz",
"integrity": "sha512-LqLPpIQANebrlxY6jKcYKdgN5DTXyyHAKnnWWjE5pPfEQ4n7j5zn7mOEEpwNZVKGqx3kKKmvplEmoBrvpgROTA==",
"license": "MIT"
}
}
}

5
package.json Normal file
View File

@@ -0,0 +1,5 @@
{
"dependencies": {
"zone.js": "^0.16.0"
}
}