forked from sanchezvem/pyrofetes-backend
Compare commits
17 Commits
5506eab8ff
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b9d00678d | |||
| 586cf6dc73 | |||
| a3380ffdf5 | |||
| 1dcb3c35f2 | |||
|
|
2af5c1e015 | ||
| 260fe71d4f | |||
| 94df917149 | |||
| 0a8258017a | |||
| 78e5a4e960 | |||
| f60d3443ca | |||
| cd7bfe618a | |||
| 038b0aa26d | |||
| 157719eae2 | |||
| a8d0b99571 | |||
| cb55f55c73 | |||
| 8699ac7437 | |||
| 4c0e7df9de |
@@ -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; }
|
||||||
}
|
}
|
||||||
@@ -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";
|
||||||
}
|
}
|
||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace PyroFetes.DTO.Login.Response;
|
namespace PyroFetes.DTO.Login.Response;
|
||||||
|
|
||||||
public class GetLoginConnectDto
|
public class GetLoginConnectDto
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,23 @@
|
|||||||
// Définition de l'espace de noms pour les DTO utilisés dans les requêtes liées aux mouvements
|
using PyroFetes.Models;
|
||||||
namespace API.DTO.Movement.Request
|
|
||||||
|
// Assure-toi d'importer tes enums
|
||||||
|
|
||||||
|
namespace PyroFetes.DTO.Movement.Request
|
||||||
{
|
{
|
||||||
// DTO utilisé pour créer un nouveau mouvement
|
|
||||||
public class CreateMovementDto
|
public class CreateMovementDto
|
||||||
{
|
{
|
||||||
// Date à laquelle le mouvement est enregistré
|
public int ProductId { get; set; }
|
||||||
public DateTime Date { get; set; }
|
|
||||||
|
|
||||||
// Date et heure de début du mouvement
|
public MovementType Type { get; set; }
|
||||||
|
|
||||||
|
public int Quantity { get; set; }
|
||||||
|
|
||||||
|
public DateTime Date { get; set; } = DateTime.Now;
|
||||||
public DateTime Start { get; set; }
|
public DateTime Start { get; set; }
|
||||||
|
|
||||||
// Date et heure d'arrivée prévue du mouvement
|
|
||||||
public DateTime Arrival { get; set; }
|
public DateTime Arrival { get; set; }
|
||||||
|
|
||||||
// Quantité de matériaux ou objets impliqués dans le mouvement
|
public int? SourceWarehouseId { get; set; }
|
||||||
public int Quantity { get; set; }
|
public int? DestinationWarehouseId { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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 d’homologation
|
// Numéro d’homologation
|
||||||
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; }
|
||||||
|
|||||||
@@ -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 d’homologation
|
// Numéro d’homologation
|
||||||
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; }
|
||||||
|
|||||||
@@ -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 d’homologation
|
// Numéro d’homologation
|
||||||
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; }
|
||||||
|
|||||||
6
PyroFetes/DTO/Refrresh/Request/RefreshTokenDto.cs
Normal file
6
PyroFetes/DTO/Refrresh/Request/RefreshTokenDto.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace PyroFetes.DTO.Refrresh.Request;
|
||||||
|
|
||||||
|
public class RefreshTokenDto
|
||||||
|
{
|
||||||
|
public string? Token { get; set; }
|
||||||
|
}
|
||||||
6
PyroFetes/DTO/Refrresh/Response/GetRefreshDto.cs
Normal file
6
PyroFetes/DTO/Refrresh/Response/GetRefreshDto.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace PyroFetes.DTO.Refrresh.Response;
|
||||||
|
|
||||||
|
public class GetRefreshDto
|
||||||
|
{
|
||||||
|
public string? Token { get; set; }
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using API.DTO.Brand.Request;
|
|
||||||
using API.DTO.Brand.Response;
|
using API.DTO.Brand.Response;
|
||||||
using FastEndpoints;
|
using FastEndpoints;
|
||||||
|
using PyroFetes.DTO.Brand.Request;
|
||||||
|
|
||||||
namespace PyroFetes.Endpoints.Brand;
|
namespace PyroFetes.Endpoints.Brand;
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -9,9 +9,8 @@ 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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using API.DTO.Movement.Request;
|
using API.DTO.Movement.Request;
|
||||||
using API.DTO.Movement.Response;
|
using API.DTO.Movement.Response;
|
||||||
using FastEndpoints;
|
using FastEndpoints;
|
||||||
|
using PyroFetes.DTO.Movement.Request;
|
||||||
|
|
||||||
namespace PyroFetes.Endpoints.Movement;
|
namespace PyroFetes.Endpoints.Movement;
|
||||||
|
|
||||||
@@ -8,8 +9,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)
|
||||||
@@ -18,9 +18,11 @@ public class CreateMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
|||||||
Models.Movement movement = new ()
|
Models.Movement movement = new ()
|
||||||
{
|
{
|
||||||
Date = req.Date,
|
Date = req.Date,
|
||||||
|
ProductId = req.ProductId,
|
||||||
Start = req.Start,
|
Start = req.Start,
|
||||||
Arrival = req.Arrival,
|
Arrival = req.Arrival,
|
||||||
Quantity = req.Quantity
|
Quantity = req.Quantity,
|
||||||
|
Type = req.Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
pyrofetesdbcontext.Movements.Add(movement);
|
pyrofetesdbcontext.Movements.Add(movement);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
@@ -29,7 +28,7 @@ public class CreateProductEndpoint(PyroFetesDbContext db)
|
|||||||
Image = req.Image!,
|
Image = req.Image!,
|
||||||
Link = req.Link!,
|
Link = req.Link!,
|
||||||
ProductCategoryId = req.ProductCategoryId,
|
ProductCategoryId = req.ProductCategoryId,
|
||||||
ClassificationId = req.ClassificationId
|
ClassificationId = req.ClassificationId,
|
||||||
};
|
};
|
||||||
|
|
||||||
db.Products.Add(product);
|
db.Products.Add(product);
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
74
PyroFetes/Endpoints/Refresh/RefreshTokenEndpoint.cs
Normal file
74
PyroFetes/Endpoints/Refresh/RefreshTokenEndpoint.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using FastEndpoints;
|
||||||
|
using FastEndpoints.Security;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using PyroFetes.DTO.Refrresh.Response;
|
||||||
|
|
||||||
|
namespace PyroFetes.Endpoints.Refresh;
|
||||||
|
|
||||||
|
public class RefreshTokenEndpoint(PyroFetesDbContext database) : EndpointWithoutRequest<GetRefreshDto>
|
||||||
|
{
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Post("/refresh");
|
||||||
|
// [Authorize] est géré ici avec les rôles
|
||||||
|
Roles("Admin", "User");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(CancellationToken ct)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1. 🚨 CORRECTION : Lire le claim 'Name' du jeton validé par le middleware
|
||||||
|
// Le claim 'Name' contient le nom d'utilisateur
|
||||||
|
string? userName = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(userName))
|
||||||
|
{
|
||||||
|
// Si le claim Name est manquant (ce qui ne devrait pas arriver)
|
||||||
|
await Send.UnauthorizedAsync(ct);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 🚨 CORRECTION : Utiliser le Nom (Name) pour la recherche BDD
|
||||||
|
// Assurez-vous que la propriété de l'entité est 'Name' et qu'elle est unique
|
||||||
|
var login = await database.Users.FirstOrDefaultAsync(x => x.Name == userName, ct);
|
||||||
|
if (login == null)
|
||||||
|
{
|
||||||
|
await Send.UnauthorizedAsync(ct);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Création du NOUVEAU jeton
|
||||||
|
string jwtToken = JwtBearer.CreateToken(
|
||||||
|
o =>
|
||||||
|
{
|
||||||
|
o.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong";
|
||||||
|
o.ExpireAt = DateTime.UtcNow.AddMinutes(15);
|
||||||
|
|
||||||
|
// Assurez-vous que les claims sont corrects pour Angular
|
||||||
|
if (login.Fonction != null) o.User.Roles.Add(login.Fonction);
|
||||||
|
|
||||||
|
// Ajouter le claim Name (Nom d'utilisateur)
|
||||||
|
o.User.Claims.Add((ClaimTypes.Name, login.Name)!);
|
||||||
|
|
||||||
|
// Si votre API mettait d'autres claims, ajoutez-les ici (ex: "Username")
|
||||||
|
// o.User.Claims.Add(("Username", login.Name)!);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Envoi de la réponse
|
||||||
|
GetRefreshDto responseDto = new()
|
||||||
|
{
|
||||||
|
Token = jwtToken
|
||||||
|
};
|
||||||
|
|
||||||
|
await Send.OkAsync(responseDto, ct);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
await Send.UnauthorizedAsync(ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
var warehouses = await db.Warehouses
|
|
||||||
.Include(w => w.WarehouseProducts)
|
|
||||||
.ThenInclude(wp => wp.Product)
|
|
||||||
.ToListAsync(ct);
|
|
||||||
|
|
||||||
var response = warehouses.Select(w => new GetWarehouseDto
|
|
||||||
{
|
{
|
||||||
Id = w.Id,
|
// 1. Chargement des entrepôts (sans tracking = plus rapide + plus safe)
|
||||||
Name = w.Name,
|
var warehouses = await db.Warehouses
|
||||||
MaxWeight = w.MaxWeight,
|
.AsNoTracking()
|
||||||
Current = w.Current,
|
.ToListAsync(ct);
|
||||||
MinWeight = w.MinWeight,
|
|
||||||
Adress = w.Address,
|
|
||||||
ZipCode = w.ZipCode,
|
|
||||||
City = w.City,
|
|
||||||
Products = w.WarehouseProducts.Select(wp => new WarehouseProductDto
|
|
||||||
{
|
|
||||||
ProductId = wp.ProductId,
|
|
||||||
ProductName = wp.Product?.Name,
|
|
||||||
Quantity = wp.Quantity
|
|
||||||
}).ToList()
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
await Send.OkAsync(response, ct);
|
// 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 =>
|
||||||
|
{
|
||||||
|
var dto = new GetWarehouseDto();
|
||||||
|
dto.GetType().GetProperty("Id")?.SetValue(dto, w.Id);
|
||||||
|
dto.GetType().GetProperty("Name")?.SetValue(dto, w.Name ?? string.Empty);
|
||||||
|
dto.GetType().GetProperty("MaxWeight")?.SetValue(dto, w.MaxWeight);
|
||||||
|
dto.GetType().GetProperty("Current")?.SetValue(dto, w.Current);
|
||||||
|
dto.GetType().GetProperty("MinWeight")?.SetValue(dto, w.MinWeight);
|
||||||
|
dto.GetType().GetProperty("Adress")?.SetValue(dto, w.Address ?? string.Empty);
|
||||||
|
dto.GetType().GetProperty("ZipCode")?.SetValue(dto, w.ZipCode);
|
||||||
|
dto.GetType().GetProperty("City")?.SetValue(dto, w.City ?? string.Empty);
|
||||||
|
|
||||||
|
// Products
|
||||||
|
var productsList = warehouseProducts
|
||||||
|
.Where(wp => wp.WarehouseId == w.Id)
|
||||||
|
.Select(wp =>
|
||||||
|
{
|
||||||
|
var prodDto = new WarehouseProductDto();
|
||||||
|
prodDto.GetType().GetProperty("ProductId")?.SetValue(prodDto, wp.ProductId);
|
||||||
|
prodDto.GetType().GetProperty("ProductName")?.SetValue(prodDto, wp.Product?.Name ?? "Produit inconnu");
|
||||||
|
prodDto.GetType().GetProperty("Quantity")?.SetValue(prodDto, wp.Quantity);
|
||||||
|
return prodDto;
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
dto.GetType().GetProperty("Products")?.SetValue(dto, productsList);
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
13
PyroFetes/Models/.idea/.gitignore
generated
vendored
@@ -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
|
|
||||||
4
PyroFetes/Models/.idea/encodings.xml
generated
4
PyroFetes/Models/.idea/encodings.xml
generated
@@ -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>
|
|
||||||
8
PyroFetes/Models/.idea/indexLayout.xml
generated
8
PyroFetes/Models/.idea/indexLayout.xml
generated
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="UserContentModel">
|
|
||||||
<attachedFolders />
|
|
||||||
<explicitIncludes />
|
|
||||||
<explicitExcludes />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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; }
|
|
||||||
}
|
|
||||||
@@ -2,18 +2,42 @@
|
|||||||
|
|
||||||
namespace PyroFetes.Models;
|
namespace PyroFetes.Models;
|
||||||
|
|
||||||
|
// 1. Définition des types possibles pour la logique métier
|
||||||
|
public enum MovementType
|
||||||
|
{
|
||||||
|
Entry, // Entrée (ex: Achat fournisseur)
|
||||||
|
Exit, // Sortie (ex: Vente, Casse)
|
||||||
|
Transfer, // Transfert entre deux entrepôts
|
||||||
|
Inventory // Ajustement manuel
|
||||||
|
}
|
||||||
|
|
||||||
public class Movement
|
public class Movement
|
||||||
{
|
{
|
||||||
[Key] public int Id { get; set; }
|
[Key]
|
||||||
[Required] public DateTime Date { get; set; }
|
public int Id { get; set; }
|
||||||
[Required] public DateTime Start {get; set;}
|
|
||||||
[Required] public DateTime Arrival {get; set;}
|
[Required]
|
||||||
[Required] public int Quantity {get; set;}
|
public DateTime Date { get; set; } = DateTime.Now;
|
||||||
|
|
||||||
public List<Product>? Products { get; set; }
|
public DateTime Start { get; set; }
|
||||||
|
public DateTime Arrival { get; set; }
|
||||||
public int? SourceWarehouseId {get; set;}
|
|
||||||
public Warehouse? SourceWarehouse {get; set;}
|
[Required]
|
||||||
public int? DestinationWarehouseId {get; set;}
|
public int Quantity { get; set; }
|
||||||
public Warehouse? DestinationWarehouse {get; set;}
|
|
||||||
|
[Required]
|
||||||
|
public MovementType Type { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public int ProductId { get; set; }
|
||||||
|
public Product? Product { get; set; }
|
||||||
|
|
||||||
|
public int? SourceWarehouseId { get; set; }
|
||||||
|
public Warehouse? SourceWarehouse { get; set; }
|
||||||
|
|
||||||
|
public int? DestinationWarehouseId { get; set; }
|
||||||
|
public Warehouse? DestinationWarehouse { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(500)]
|
||||||
|
public string? Comment { get; set; }
|
||||||
}
|
}
|
||||||
@@ -8,13 +8,13 @@ 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; }
|
public string? Image { get; set; }
|
||||||
[Required, MaxLength(200)] public string? Link { get; set; }
|
[MaxLength(200)] public string? Link { get; set; }
|
||||||
[Required] public int MinimalQuantity { get; set; }
|
public int MinimalQuantity { get; set; }
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
[Required] public int ClassificationId { get; set; }
|
[Required] public int ClassificationId { get; set; }
|
||||||
@@ -23,8 +23,7 @@ namespace PyroFetes.Models
|
|||||||
[Required] public int ProductCategoryId { get; set; }
|
[Required] public int ProductCategoryId { get; set; }
|
||||||
public ProductCategory? ProductCategory { get; set; }
|
public ProductCategory? ProductCategory { get; set; }
|
||||||
|
|
||||||
[Required] public int MovementId {get; set;}
|
public List<Movement>? Movements { get; set; }
|
||||||
public Movement? Movement {get; set;}
|
|
||||||
|
|
||||||
public List<ProductDelivery>? ProductDeliveries { get; set; }
|
public List<ProductDelivery>? ProductDeliveries { get; set; }
|
||||||
public List<Brand>? Brands { get; set; }
|
public List<Brand>? Brands { get; set; }
|
||||||
@@ -36,6 +35,5 @@ namespace PyroFetes.Models
|
|||||||
public List<WarehouseProduct>? WarehouseProducts { get; set; }
|
public List<WarehouseProduct>? WarehouseProducts { get; set; }
|
||||||
public List<ProductTimecode>? ProductTimecodes { get; set; }
|
public List<ProductTimecode>? ProductTimecodes { get; set; }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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; }
|
||||||
|
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace PyroFetes.Models;
|
namespace PyroFetes.Models;
|
||||||
|
|
||||||
@@ -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; }
|
||||||
|
|||||||
@@ -1,29 +1,50 @@
|
|||||||
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();
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<RollForward>Major</RollForward>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -14,8 +15,8 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.19" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.19" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.20" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.20" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.20">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.20">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.20" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.20" />
|
||||||
<PackageReference Include="PasswordGenerator" Version="2.1.0" />
|
<PackageReference Include="PasswordGenerator" Version="2.1.0" />
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ namespace PyroFetes;
|
|||||||
|
|
||||||
public class PyroFetesDbContext : DbContext
|
public class PyroFetesDbContext : DbContext
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// Entities
|
// Entities
|
||||||
public DbSet<Availability> Availabilities { get; set; }
|
public DbSet<Availability> Availabilities { get; set; }
|
||||||
public DbSet<Brand> Brands { get; set; }
|
public DbSet<Brand> Brands { get; set; }
|
||||||
@@ -49,16 +51,15 @@ 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)
|
||||||
{
|
{
|
||||||
string connectionString =
|
string connectionString =
|
||||||
"Server=romaric-thibault.fr;" +
|
"Server=romaric-thibault.fr;" +
|
||||||
"Database=PyroFetes;" +
|
"Database=PyroMana;" +
|
||||||
"User Id=pyrofetes;" +
|
"User Id=matheo;" +
|
||||||
"Password=Crablike8-Fringe-Swimmable;" +
|
"Password=Onto9-Cage-Afflicted;" +
|
||||||
"TrustServerCertificate=true;";
|
"TrustServerCertificate=true;";
|
||||||
|
|
||||||
optionsBuilder.UseSqlServer(connectionString);
|
optionsBuilder.UseSqlServer(connectionString);
|
||||||
|
|||||||
281
PyroFetes/README.md
Normal file
281
PyroFetes/README.md
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
# 🎆 Pyrofêtes — Backend
|
||||||
|
|
||||||
|
> API REST de gestion des entrepôts et produits pyrotechniques, développée avec **C#**, **ASP.NET Core** et **FastEndpoints**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Stack technique
|
||||||
|
|
||||||
|
| Technologie | Rôle |
|
||||||
|
|---|---|
|
||||||
|
| [C# / .NET 8](https://dotnet.microsoft.com/) | Langage et runtime principal |
|
||||||
|
| [ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/) | Framework web |
|
||||||
|
| [FastEndpoints](https://fast-endpoints.com/) | Bibliothèque d'endpoints REST performants |
|
||||||
|
| Entity Framework Core | ORM pour l'accès à la base de données |
|
||||||
|
| SQL Server | Base de données relationnelle |
|
||||||
|
| JWT Bearer | Authentification par token |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 Structure du projet
|
||||||
|
|
||||||
|
```
|
||||||
|
Pyrofetes.API/
|
||||||
|
│
|
||||||
|
├── Models/ # Entités de la base de données (EF Core)
|
||||||
|
│
|
||||||
|
├── DTO/ # Objets de transfert de données
|
||||||
|
│ ├── Brand/
|
||||||
|
│ │ ├── Request/
|
||||||
|
│ │ │ ├── CreateBrandDto.cs
|
||||||
|
│ │ │ └── UpdateBrandDto.cs
|
||||||
|
│ │ └── Response/
|
||||||
|
│ │ └── GetBrandDto.cs
|
||||||
|
│ ├── Classification/
|
||||||
|
│ ├── Color/
|
||||||
|
│ ├── Effect/
|
||||||
|
│ ├── Login/
|
||||||
|
│ ├── Material/
|
||||||
|
│ ├── Movement/
|
||||||
|
│ ├── Product/
|
||||||
|
│ ├── ProductCategory/
|
||||||
|
│ ├── ProductColor/
|
||||||
|
│ ├── ProductEffect/
|
||||||
|
│ ├── ProductSupplierPrice/
|
||||||
|
│ ├── ProductWarehouse/
|
||||||
|
│ ├── Refrresh/ # Token refresh
|
||||||
|
│ ├── Supplier/
|
||||||
|
│ └── Warehouse/
|
||||||
|
│
|
||||||
|
├── Endpoints/ # Endpoints FastEndpoints (CRUD par domaine)
|
||||||
|
│ ├── Brand/
|
||||||
|
│ │ ├── CreateBrandEndpoint.cs
|
||||||
|
│ │ ├── DeleteBrandEndpoint.cs
|
||||||
|
│ │ ├── GetAllBrandsEndpoint.cs
|
||||||
|
│ │ ├── GetBrandEndpoint.cs
|
||||||
|
│ │ └── UpdateBrandEndpoint.cs
|
||||||
|
│ ├── Classification/
|
||||||
|
│ ├── Color/
|
||||||
|
│ ├── Effect/
|
||||||
|
│ ├── Login/
|
||||||
|
│ ├── Material/
|
||||||
|
│ ├── Movement/
|
||||||
|
│ ├── Product/
|
||||||
|
│ ├── ProductCategory/
|
||||||
|
│ ├── Refresh/ # Refresh token JWT
|
||||||
|
│ ├── Supplier/
|
||||||
|
│ └── Warehouse/
|
||||||
|
│
|
||||||
|
├── Data/ # Contexte Entity Framework Core
|
||||||
|
│ └── AppDbContext.cs
|
||||||
|
│
|
||||||
|
├── Migrations/ # Migrations EF Core
|
||||||
|
├── appsettings.json # Configuration production
|
||||||
|
├── appsettings.Development.json # Configuration développement
|
||||||
|
└── Program.cs # Point d'entrée et configuration des services
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Installation et lancement
|
||||||
|
|
||||||
|
### Prérequis
|
||||||
|
|
||||||
|
- [.NET SDK](https://dotnet.microsoft.com/download) >= 8.0
|
||||||
|
- SQL Server en cours d'exécution (local ou distant)
|
||||||
|
- [Entity Framework CLI](https://learn.microsoft.com/en-us/ef/core/cli/dotnet)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet tool install --global dotnet-ef
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Cloner le dépôt
|
||||||
|
git clone https://gitea.btssio-poitiers.fr/reignem/PyroFetes-Sujet1.git
|
||||||
|
cd pyrofetes-backend
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migrations et base de données
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Créer la base de données et appliquer les migrations
|
||||||
|
dotnet ef database update
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lancement
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|
||||||
|
L'API sera disponible sur [http://localhost:5000](http://localhost:5000)
|
||||||
|
La documentation Swagger sera accessible sur [http://localhost:5000/swagger](http://localhost:5000/swagger)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Configuration FastEndpoints + CORS
|
||||||
|
|
||||||
|
Dans `Program.cs` :
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
builder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("AllowAngular", policy =>
|
||||||
|
policy.WithOrigins("http://localhost:4200")
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod());
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddFastEndpoints();
|
||||||
|
builder.Services.AddJWTBearerAuth("votre-cle-secrete");
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
app.UseCors("AllowAngular");
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.UseFastEndpoints();
|
||||||
|
app.Run();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Anatomie d'un endpoint
|
||||||
|
|
||||||
|
Chaque endpoint suit le pattern **Request → Handler → Response** de FastEndpoints :
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Endpoints/Brand/GetAllBrandsEndpoint.cs
|
||||||
|
public class GetAllBrandsEndpoint : EndpointWithoutRequest<List<GetBrandDto>>
|
||||||
|
{
|
||||||
|
private readonly AppDbContext _db;
|
||||||
|
|
||||||
|
public GetAllBrandsEndpoint(AppDbContext db) => _db = db;
|
||||||
|
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Get("/api/brands");
|
||||||
|
Roles("Admin", "User");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(CancellationToken ct)
|
||||||
|
{
|
||||||
|
var brands = await _db.Brands
|
||||||
|
.Select(b => new GetBrandDto { Id = b.Id, Name = b.Name })
|
||||||
|
.ToListAsync(ct);
|
||||||
|
|
||||||
|
await SendOkAsync(brands, ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern DTO
|
||||||
|
|
||||||
|
```
|
||||||
|
DTO/
|
||||||
|
└── Brand/
|
||||||
|
├── Request/
|
||||||
|
│ ├── CreateBrandDto.cs ← payload entrant (POST)
|
||||||
|
│ └── UpdateBrandDto.cs ← payload entrant (PUT)
|
||||||
|
└── Response/
|
||||||
|
└── GetBrandDto.cs ← payload sortant (GET)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Endpoints API
|
||||||
|
|
||||||
|
> Tous les endpoints (sauf `/api/auth/*` et `/api/auth/refresh`) requièrent un header `Authorization: Bearer <token>`.
|
||||||
|
|
||||||
|
### Authentification
|
||||||
|
|
||||||
|
| Méthode | Route | Description | Auth |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `POST` | `/api/auth/login` | Connexion, retourne JWT + refresh token | ❌ |
|
||||||
|
| `POST` | `/api/auth/refresh` | Renouvellement du JWT via refresh token | ❌ |
|
||||||
|
|
||||||
|
### Marques (Brand)
|
||||||
|
|
||||||
|
| Méthode | Route | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET` | `/api/brands` | Liste toutes les marques |
|
||||||
|
| `GET` | `/api/brands/{id}` | Détail d'une marque |
|
||||||
|
| `POST` | `/api/brands` | Créer une marque |
|
||||||
|
| `PUT` | `/api/brands/{id}` | Modifier une marque |
|
||||||
|
| `DELETE` | `/api/brands/{id}` | Supprimer une marque |
|
||||||
|
|
||||||
|
### Produits (Product)
|
||||||
|
|
||||||
|
| Méthode | Route | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET` | `/api/products` | Liste tous les produits |
|
||||||
|
| `GET` | `/api/products/{id}` | Détail d'un produit |
|
||||||
|
| `POST` | `/api/products` | Créer un produit |
|
||||||
|
| `PUT` | `/api/products/{id}` | Modifier un produit |
|
||||||
|
| `DELETE` | `/api/products/{id}` | Supprimer un produit |
|
||||||
|
|
||||||
|
### Entrepôts (Warehouse)
|
||||||
|
|
||||||
|
| Méthode | Route | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET` | `/api/warehouses` | Liste tous les entrepôts |
|
||||||
|
| `GET` | `/api/warehouses/{id}` | Détail d'un entrepôt |
|
||||||
|
| `POST` | `/api/warehouses` | Créer un entrepôt |
|
||||||
|
| `PUT` | `/api/warehouses/{id}` | Modifier un entrepôt |
|
||||||
|
| `DELETE` | `/api/warehouses/{id}` | Supprimer un entrepôt |
|
||||||
|
|
||||||
|
### Fournisseurs (Supplier)
|
||||||
|
|
||||||
|
| Méthode | Route | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET` | `/api/suppliers` | Liste tous les fournisseurs |
|
||||||
|
| `GET` | `/api/suppliers/{id}` | Détail d'un fournisseur |
|
||||||
|
| `POST` | `/api/suppliers` | Créer un fournisseur |
|
||||||
|
| `PUT` | `/api/suppliers/{id}` | Modifier un fournisseur |
|
||||||
|
| `DELETE` | `/api/suppliers/{id}` | Supprimer un fournisseur |
|
||||||
|
|
||||||
|
### Autres domaines disponibles
|
||||||
|
|
||||||
|
| Domaine | Préfixe route |
|
||||||
|
|---|---|
|
||||||
|
| Classifications | `/api/classifications` |
|
||||||
|
| Couleurs | `/api/colors` |
|
||||||
|
| Effets | `/api/effects` |
|
||||||
|
| Matériaux | `/api/materials` |
|
||||||
|
| Mouvements de stock | `/api/movements` |
|
||||||
|
| Catégories produit | `/api/product-categories` |
|
||||||
|
| Couleurs produit | `/api/product-colors` |
|
||||||
|
| Effets produit | `/api/product-effects` |
|
||||||
|
| Prix fournisseur produit | `/api/product-supplier-prices` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Authentification JWT
|
||||||
|
|
||||||
|
### Flux d'authentification
|
||||||
|
|
||||||
|
```
|
||||||
|
Client (Angular) API (FastEndpoints)
|
||||||
|
│ │
|
||||||
|
│── POST /api/auth/login ──▶│
|
||||||
|
│ │ Vérifie credentials
|
||||||
|
│◀── { token, refreshToken }│
|
||||||
|
│ │
|
||||||
|
│── GET /api/... ──────────▶│
|
||||||
|
│ Authorization: Bearer │ Valide le JWT
|
||||||
|
│◀── 200 OK ────────────────│
|
||||||
|
│ │
|
||||||
|
│── POST /api/auth/refresh ▶│ (token expiré)
|
||||||
|
│◀── { newToken } ──────────│
|
||||||
|
```
|
||||||
|
|
||||||
|
### Header requis
|
||||||
|
|
||||||
|
```
|
||||||
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📄 Licence
|
||||||
|
|
||||||
|
Ce projet est à usage interne — © Pyrofêtes. Tous droits réservés.
|
||||||
303
README.md
303
README.md
@@ -1,50 +1,281 @@
|
|||||||
# Gestionnaire de Stocks et Commandes
|
# 🎆 Pyrofêtes — Backend
|
||||||
|
|
||||||
Cette application web permet de **suivre les stocks**, **automatiser les commandes fournisseurs** et **gérer le cycle complet d’approvisionnement**.
|
> API REST de gestion des entrepôts et produits pyrotechniques, développée avec **C#**, **ASP.NET Core** et **FastEndpoints**.
|
||||||
Elle est conçue pour simplifier le travail des entreprises en offrant une vue en temps réel sur les produits, leurs fournisseurs et l’état des livraisons.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✨ Fonctionnalités principales
|
## 🛠️ Stack technique
|
||||||
|
|
||||||
### 1️⃣ Suivi et réapprovisionnement des stocks
|
| Technologie | Rôle |
|
||||||
- Définissez un **niveau minimal de stock** pour chaque produit.
|
|---|---|
|
||||||
- Surveillez les **niveaux en temps réel** grâce à une interface claire.
|
| [C# / .NET 8](https://dotnet.microsoft.com/) | Langage et runtime principal |
|
||||||
- Lorsqu’un produit atteint ou descend sous son seuil minimal, le système **génère automatiquement un bon de commande** pour le réapprovisionner.
|
| [ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/) | Framework web |
|
||||||
|
| [FastEndpoints](https://fast-endpoints.com/) | Bibliothèque d'endpoints REST performants |
|
||||||
### 2️⃣ Gestion des fournisseurs
|
| Entity Framework Core | ORM pour l'accès à la base de données |
|
||||||
- Enregistrez les informations complètes des fournisseurs : nom, adresse, coordonnées, produits fournis, délais de livraison.
|
| SQL Server | Base de données relationnelle |
|
||||||
- **Associez un ou plusieurs fournisseurs** à chaque produit.
|
| JWT Bearer | Authentification par token |
|
||||||
- Lorsqu’un bon de commande est créé, le système **propose automatiquement les fournisseurs appropriés**.
|
|
||||||
|
|
||||||
### 3️⃣ Devis et bons de commande
|
|
||||||
- Créez des **devis personnalisés** : sélection des produits, quantités, prix, ajout d’un logo, message ou conditions de vente.
|
|
||||||
- **Imprimez ou exportez** vos devis au format PDF.
|
|
||||||
- Générez des **bons de commande** en quelques clics, avec personnalisation (logo, conditions d’achat) et exportation en PDF.
|
|
||||||
|
|
||||||
### 4️⃣ Suivi des livraisons
|
|
||||||
- **Transformez un bon de commande en bon de livraison** dès l’expédition des produits par le fournisseur.
|
|
||||||
- Enregistrez toutes les informations importantes : date d’expédition, transporteur, numéro de suivi, date prévue et date effective de livraison.
|
|
||||||
- Recevez des **alertes en cas de retard**.
|
|
||||||
- Gérez la **réception des produits** et vérifiez leur conformité.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🗂️ Livrables prévus
|
## 📁 Structure du projet
|
||||||
- **Modèle de données** : diagramme de classes commun à tous les groupes.
|
|
||||||
- **Interface utilisateur** : maquettes ou prototypes interactifs.
|
```
|
||||||
- **Code source commenté** pour une meilleure compréhension.
|
Pyrofetes.API/
|
||||||
- **Documentation technique** : description des fonctionnalités, architecture de l’application et API.
|
│
|
||||||
|
├── Models/ # Entités de la base de données (EF Core)
|
||||||
|
│
|
||||||
|
├── DTO/ # Objets de transfert de données
|
||||||
|
│ ├── Brand/
|
||||||
|
│ │ ├── Request/
|
||||||
|
│ │ │ ├── CreateBrandDto.cs
|
||||||
|
│ │ │ └── UpdateBrandDto.cs
|
||||||
|
│ │ └── Response/
|
||||||
|
│ │ └── GetBrandDto.cs
|
||||||
|
│ ├── Classification/
|
||||||
|
│ ├── Color/
|
||||||
|
│ ├── Effect/
|
||||||
|
│ ├── Login/
|
||||||
|
│ ├── Material/
|
||||||
|
│ ├── Movement/
|
||||||
|
│ ├── Product/
|
||||||
|
│ ├── ProductCategory/
|
||||||
|
│ ├── ProductColor/
|
||||||
|
│ ├── ProductEffect/
|
||||||
|
│ ├── ProductSupplierPrice/
|
||||||
|
│ ├── ProductWarehouse/
|
||||||
|
│ ├── Refrresh/ # Token refresh
|
||||||
|
│ ├── Supplier/
|
||||||
|
│ └── Warehouse/
|
||||||
|
│
|
||||||
|
├── Endpoints/ # Endpoints FastEndpoints (CRUD par domaine)
|
||||||
|
│ ├── Brand/
|
||||||
|
│ │ ├── CreateBrandEndpoint.cs
|
||||||
|
│ │ ├── DeleteBrandEndpoint.cs
|
||||||
|
│ │ ├── GetAllBrandsEndpoint.cs
|
||||||
|
│ │ ├── GetBrandEndpoint.cs
|
||||||
|
│ │ └── UpdateBrandEndpoint.cs
|
||||||
|
│ ├── Classification/
|
||||||
|
│ ├── Color/
|
||||||
|
│ ├── Effect/
|
||||||
|
│ ├── Login/
|
||||||
|
│ ├── Material/
|
||||||
|
│ ├── Movement/
|
||||||
|
│ ├── Product/
|
||||||
|
│ ├── ProductCategory/
|
||||||
|
│ ├── Refresh/ # Refresh token JWT
|
||||||
|
│ ├── Supplier/
|
||||||
|
│ └── Warehouse/
|
||||||
|
│
|
||||||
|
├── Data/ # Contexte Entity Framework Core
|
||||||
|
│ └── AppDbContext.cs
|
||||||
|
│
|
||||||
|
├── Migrations/ # Migrations EF Core
|
||||||
|
├── appsettings.json # Configuration production
|
||||||
|
├── appsettings.Development.json # Configuration développement
|
||||||
|
└── Program.cs # Point d'entrée et configuration des services
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 👥 Équipe
|
## 🚀 Installation et lancement
|
||||||
- **Mathys**
|
|
||||||
- **Enzo**
|
### Prérequis
|
||||||
- **Cristiano**
|
|
||||||
- **Arsène**
|
- [.NET SDK](https://dotnet.microsoft.com/download) >= 8.0
|
||||||
|
- SQL Server en cours d'exécution (local ou distant)
|
||||||
|
- [Entity Framework CLI](https://learn.microsoft.com/en-us/ef/core/cli/dotnet)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet tool install --global dotnet-ef
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Cloner le dépôt
|
||||||
|
git clone https://gitea.btssio-poitiers.fr/reignem/PyroFetes-Sujet1.git
|
||||||
|
cd pyrofetes-backend
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migrations et base de données
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Créer la base de données et appliquer les migrations
|
||||||
|
dotnet ef database update
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lancement
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|
||||||
|
L'API sera disponible sur [http://localhost:5000](http://localhost:5000)
|
||||||
|
La documentation Swagger sera accessible sur [http://localhost:5000/swagger](http://localhost:5000/swagger)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Objectif
|
## ⚙️ Configuration FastEndpoints + CORS
|
||||||
Fournir un outil complet pour automatiser la gestion des stocks et des commandes, réduisant les erreurs humaines, améliorant le suivi des livraisons et facilitant la communication avec les fournisseurs.
|
|
||||||
|
Dans `Program.cs` :
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
builder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("AllowAngular", policy =>
|
||||||
|
policy.WithOrigins("http://localhost:4200")
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod());
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddFastEndpoints();
|
||||||
|
builder.Services.AddJWTBearerAuth("votre-cle-secrete");
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
app.UseCors("AllowAngular");
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.UseFastEndpoints();
|
||||||
|
app.Run();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Anatomie d'un endpoint
|
||||||
|
|
||||||
|
Chaque endpoint suit le pattern **Request → Handler → Response** de FastEndpoints :
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Endpoints/Brand/GetAllBrandsEndpoint.cs
|
||||||
|
public class GetAllBrandsEndpoint : EndpointWithoutRequest<List<GetBrandDto>>
|
||||||
|
{
|
||||||
|
private readonly AppDbContext _db;
|
||||||
|
|
||||||
|
public GetAllBrandsEndpoint(AppDbContext db) => _db = db;
|
||||||
|
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Get("/api/brands");
|
||||||
|
Roles("Admin", "User");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(CancellationToken ct)
|
||||||
|
{
|
||||||
|
var brands = await _db.Brands
|
||||||
|
.Select(b => new GetBrandDto { Id = b.Id, Name = b.Name })
|
||||||
|
.ToListAsync(ct);
|
||||||
|
|
||||||
|
await SendOkAsync(brands, ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern DTO
|
||||||
|
|
||||||
|
```
|
||||||
|
DTO/
|
||||||
|
└── Brand/
|
||||||
|
├── Request/
|
||||||
|
│ ├── CreateBrandDto.cs ← payload entrant (POST)
|
||||||
|
│ └── UpdateBrandDto.cs ← payload entrant (PUT)
|
||||||
|
└── Response/
|
||||||
|
└── GetBrandDto.cs ← payload sortant (GET)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 Endpoints API
|
||||||
|
|
||||||
|
> Tous les endpoints (sauf `/api/auth/*` et `/api/auth/refresh`) requièrent un header `Authorization: Bearer <token>`.
|
||||||
|
|
||||||
|
### Authentification
|
||||||
|
|
||||||
|
| Méthode | Route | Description | Auth |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `POST` | `/api/auth/login` | Connexion, retourne JWT + refresh token | ❌ |
|
||||||
|
| `POST` | `/api/auth/refresh` | Renouvellement du JWT via refresh token | ❌ |
|
||||||
|
|
||||||
|
### Marques (Brand)
|
||||||
|
|
||||||
|
| Méthode | Route | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET` | `/api/brands` | Liste toutes les marques |
|
||||||
|
| `GET` | `/api/brands/{id}` | Détail d'une marque |
|
||||||
|
| `POST` | `/api/brands` | Créer une marque |
|
||||||
|
| `PUT` | `/api/brands/{id}` | Modifier une marque |
|
||||||
|
| `DELETE` | `/api/brands/{id}` | Supprimer une marque |
|
||||||
|
|
||||||
|
### Produits (Product)
|
||||||
|
|
||||||
|
| Méthode | Route | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET` | `/api/products` | Liste tous les produits |
|
||||||
|
| `GET` | `/api/products/{id}` | Détail d'un produit |
|
||||||
|
| `POST` | `/api/products` | Créer un produit |
|
||||||
|
| `PUT` | `/api/products/{id}` | Modifier un produit |
|
||||||
|
| `DELETE` | `/api/products/{id}` | Supprimer un produit |
|
||||||
|
|
||||||
|
### Entrepôts (Warehouse)
|
||||||
|
|
||||||
|
| Méthode | Route | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET` | `/api/warehouses` | Liste tous les entrepôts |
|
||||||
|
| `GET` | `/api/warehouses/{id}` | Détail d'un entrepôt |
|
||||||
|
| `POST` | `/api/warehouses` | Créer un entrepôt |
|
||||||
|
| `PUT` | `/api/warehouses/{id}` | Modifier un entrepôt |
|
||||||
|
| `DELETE` | `/api/warehouses/{id}` | Supprimer un entrepôt |
|
||||||
|
|
||||||
|
### Fournisseurs (Supplier)
|
||||||
|
|
||||||
|
| Méthode | Route | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET` | `/api/suppliers` | Liste tous les fournisseurs |
|
||||||
|
| `GET` | `/api/suppliers/{id}` | Détail d'un fournisseur |
|
||||||
|
| `POST` | `/api/suppliers` | Créer un fournisseur |
|
||||||
|
| `PUT` | `/api/suppliers/{id}` | Modifier un fournisseur |
|
||||||
|
| `DELETE` | `/api/suppliers/{id}` | Supprimer un fournisseur |
|
||||||
|
|
||||||
|
### Autres domaines disponibles
|
||||||
|
|
||||||
|
| Domaine | Préfixe route |
|
||||||
|
|---|---|
|
||||||
|
| Classifications | `/api/classifications` |
|
||||||
|
| Couleurs | `/api/colors` |
|
||||||
|
| Effets | `/api/effects` |
|
||||||
|
| Matériaux | `/api/materials` |
|
||||||
|
| Mouvements de stock | `/api/movements` |
|
||||||
|
| Catégories produit | `/api/product-categories` |
|
||||||
|
| Couleurs produit | `/api/product-colors` |
|
||||||
|
| Effets produit | `/api/product-effects` |
|
||||||
|
| Prix fournisseur produit | `/api/product-supplier-prices` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Authentification JWT
|
||||||
|
|
||||||
|
### Flux d'authentification
|
||||||
|
|
||||||
|
```
|
||||||
|
Client (Angular) API (FastEndpoints)
|
||||||
|
│ │
|
||||||
|
│── POST /api/auth/login ──▶│
|
||||||
|
│ │ Vérifie credentials
|
||||||
|
│◀── { token, refreshToken }│
|
||||||
|
│ │
|
||||||
|
│── GET /api/... ──────────▶│
|
||||||
|
│ Authorization: Bearer │ Valide le JWT
|
||||||
|
│◀── 200 OK ────────────────│
|
||||||
|
│ │
|
||||||
|
│── POST /api/auth/refresh ▶│ (token expiré)
|
||||||
|
│◀── { newToken } ──────────│
|
||||||
|
```
|
||||||
|
|
||||||
|
### Header requis
|
||||||
|
|
||||||
|
```
|
||||||
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📄 Licence
|
||||||
|
|
||||||
|
Ce projet est à usage interne — © Pyrofêtes. Tous droits réservés.
|
||||||
18
package-lock.json
generated
Normal file
18
package-lock.json
generated
Normal 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
5
package.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"zone.js": "^0.16.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user