forked from sanchezvem/pyrofetes-backend
Compare commits
9 Commits
f60d3443ca
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b9d00678d | |||
| 586cf6dc73 | |||
| a3380ffdf5 | |||
| 1dcb3c35f2 | |||
|
|
2af5c1e015 | ||
| 260fe71d4f | |||
| 94df917149 | |||
| 0a8258017a | |||
| 78e5a4e960 |
7
PyroFetes/DTO/Login/Request/ConnectLoginDto.cs
Normal file
7
PyroFetes/DTO/Login/Request/ConnectLoginDto.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace PyroFetes.DTO.Login.Request;
|
||||
|
||||
public class ConnectLoginDto
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
public string? Password { get; set; }
|
||||
}
|
||||
24
PyroFetes/DTO/Login/Request/CreateLoginDto.cs
Normal file
24
PyroFetes/DTO/Login/Request/CreateLoginDto.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
// Nécessaire pour les validations
|
||||
|
||||
namespace PyroFetes.DTO.Login.Request;
|
||||
|
||||
public class CreateLoginDto
|
||||
{
|
||||
[Required(ErrorMessage = "Le nom est requis.")]
|
||||
[StringLength(50, MinimumLength = 3, ErrorMessage = "L'identifiant doit faire entre 3 et 50 caractères.")]
|
||||
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";
|
||||
}
|
||||
8
PyroFetes/DTO/Login/Request/UpdateLoginDto.cs
Normal file
8
PyroFetes/DTO/Login/Request/UpdateLoginDto.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace PyroFetes.DTO.Login.Request;
|
||||
|
||||
public class UpdateLoginDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Password { get; set; }
|
||||
}
|
||||
6
PyroFetes/DTO/Login/Response/GetLoginConnectDto.cs
Normal file
6
PyroFetes/DTO/Login/Response/GetLoginConnectDto.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace PyroFetes.DTO.Login.Response;
|
||||
|
||||
public class GetLoginConnectDto
|
||||
{
|
||||
public string? Token { get; set; }
|
||||
}
|
||||
10
PyroFetes/DTO/Login/Response/GetLoginDto.cs
Normal file
10
PyroFetes/DTO/Login/Response/GetLoginDto.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace PyroFetes.DTO.Login.Response;
|
||||
|
||||
public class GetLoginDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Name { get; set; } = string.Empty;
|
||||
public string? Email { get; set; } = string.Empty;
|
||||
public string? Password { get; set; } = string.Empty;
|
||||
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
|
||||
namespace API.DTO.Movement.Request
|
||||
using PyroFetes.Models;
|
||||
|
||||
// Assure-toi d'importer tes enums
|
||||
|
||||
namespace PyroFetes.DTO.Movement.Request
|
||||
{
|
||||
// DTO utilisé pour créer un nouveau mouvement
|
||||
public class CreateMovementDto
|
||||
{
|
||||
// Date à laquelle le mouvement est enregistré
|
||||
public DateTime Date { get; set; }
|
||||
public int ProductId { 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; }
|
||||
|
||||
// Date et heure d'arrivée prévue du mouvement
|
||||
public DateTime Arrival { get; set; }
|
||||
|
||||
// Quantité de matériaux ou objets impliqués dans le mouvement
|
||||
public int Quantity { get; set; }
|
||||
public int? SourceWarehouseId { get; set; }
|
||||
public int? DestinationWarehouseId { 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; }
|
||||
}
|
||||
@@ -9,7 +9,6 @@ public class CreateBrandEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/brands");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateBrandDto req, CancellationToken ct)
|
||||
|
||||
@@ -13,7 +13,6 @@ public class DeleteBrandEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/brands/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteBrandRequest req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class GetAllBrandsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/brands");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
|
||||
@@ -14,7 +14,6 @@ public class GetBrandEndpoint(PyroFetesDbContext pyrofetesdbcontext) :Endpoint<G
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/brands/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetBrandRequest req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class UpdateBrandEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
|
||||
public override void Configure()
|
||||
{
|
||||
Put("/brands/{Id}");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateBrandDto req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class CreateClassificationEndpoint(PyroFetesDbContext pyrofetesdbcontext)
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/classifications");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateClassificationDto req, CancellationToken ct)
|
||||
|
||||
@@ -13,7 +13,6 @@ public class DeleteClassificationEndpoint(PyroFetesDbContext libraryDbContext) :
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/classifications/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteClassificationRequest req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class GetAllClassificationsEndpoint(PyroFetesDbContext pyrofetesdbcontext
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/classifications");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
|
||||
@@ -14,7 +14,6 @@ public class GetClassificationEndpoint(PyroFetesDbContext pyrofetesdbcontext) :E
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/classifications/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetClassificationRequest req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class UpdateClassificationEndpoint(PyroFetesDbContext pyrofetesdbcontext)
|
||||
public override void Configure()
|
||||
{
|
||||
Put("/classifications");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateClassificationDto req, CancellationToken ct)
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
using API.DTO.Color.Request;
|
||||
using API.DTO.Color.Response;
|
||||
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 override void Configure() //Configuration de l'endpoint
|
||||
{
|
||||
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
|
||||
|
||||
@@ -13,7 +13,6 @@ public class DeleteColorEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/colors/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteColorRequest req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class GetAllColorsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/colors");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
|
||||
@@ -14,7 +14,6 @@ public class GetColorEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoint<
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/colors/{@id}", x => new { x.Id});
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetColorRequest req, CancellationToken ct)
|
||||
|
||||
@@ -10,7 +10,6 @@ public class UpdateColorEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
|
||||
public override void Configure()
|
||||
{
|
||||
Put("/colors/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateColorDto req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class CreateEffectEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/effects");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateEffectDto req, CancellationToken ct)
|
||||
|
||||
@@ -12,7 +12,6 @@ public class DeleteEffectEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/effects/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteEffectRequest req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class GetAllEffectsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endp
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/effects");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
|
||||
@@ -14,7 +14,6 @@ public class GetEffectEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoint
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/effects/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetEffectRequest req, CancellationToken ct)
|
||||
|
||||
@@ -10,7 +10,6 @@ public class UpdateEffectEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpo
|
||||
public override void Configure()
|
||||
{
|
||||
Put("/effects/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateEffectDto req, CancellationToken ct)
|
||||
|
||||
53
PyroFetes/Endpoints/Login/CreateLoginEndpoint.cs
Normal file
53
PyroFetes/Endpoints/Login/CreateLoginEndpoint.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using FastEndpoints;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PasswordGenerator;
|
||||
using PyroFetes.DTO.Login.Request;
|
||||
using PyroFetes.DTO.Login.Response;
|
||||
|
||||
namespace PyroFetes.Endpoints.Login;
|
||||
|
||||
public class CreateLoginEndpoint(PyroFetesDbContext database) : Endpoint<CreateLoginDto, GetLoginDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/logins");
|
||||
//Roles("Admin");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
Models.User login = new Models.User()
|
||||
{
|
||||
Name = req.Name,
|
||||
Email = req.Email,
|
||||
Password = BCrypt.Net.BCrypt.HashPassword(req.Password + salt),
|
||||
Salt = salt,
|
||||
|
||||
Fonction = string.IsNullOrEmpty(req.Fonction) ? "User" : req.Fonction
|
||||
};
|
||||
|
||||
database.Users.Add(login);
|
||||
await database.SaveChangesAsync(ct);
|
||||
|
||||
GetLoginDto responseDto = new()
|
||||
{
|
||||
Id = login.Id,
|
||||
Name = login.Name,
|
||||
Email = login.Email,
|
||||
Fonction = login.Fonction
|
||||
};
|
||||
|
||||
await Send.OkAsync(responseDto, ct);
|
||||
}
|
||||
}
|
||||
34
PyroFetes/Endpoints/Login/DeleteLoginEndpoint.cs
Normal file
34
PyroFetes/Endpoints/Login/DeleteLoginEndpoint.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using FastEndpoints;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace PyroFetes.Endpoints.Login;
|
||||
|
||||
public class DeleteLoginRequest
|
||||
{
|
||||
public int Id { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteLoginEndpoint(PyroFetesDbContext database) : Endpoint<DeleteLoginRequest>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/logins/{@Id}", x => new {x.Id});
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteLoginRequest req, CancellationToken ct)
|
||||
{
|
||||
Models.User? login = await database.Users.SingleOrDefaultAsync(x => x.Id == req.Id, ct);
|
||||
|
||||
if (login == null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
database.Users.Remove(login);
|
||||
await database.SaveChangesAsync(ct);
|
||||
|
||||
await Send.NoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
29
PyroFetes/Endpoints/Login/GetAllLoginEndpoint.cs
Normal file
29
PyroFetes/Endpoints/Login/GetAllLoginEndpoint.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using FastEndpoints;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PyroFetes.DTO.Login.Response;
|
||||
|
||||
namespace PyroFetes.Endpoints.Login;
|
||||
|
||||
public class GetAllLoginEndpoint(PyroFetesDbContext database) : EndpointWithoutRequest<List<GetLoginDto>>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/logins");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
List<GetLoginDto> logins = await database.Users
|
||||
.Select(login => new GetLoginDto()
|
||||
{
|
||||
Id = login.Id,
|
||||
Name = login.Name,
|
||||
Password = login.Password,
|
||||
Fonction = login.Fonction
|
||||
})
|
||||
.ToListAsync(ct);
|
||||
|
||||
await Send.OkAsync(logins, ct);
|
||||
}
|
||||
}
|
||||
40
PyroFetes/Endpoints/Login/GetLoginEndpoint.cs
Normal file
40
PyroFetes/Endpoints/Login/GetLoginEndpoint.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using FastEndpoints;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PyroFetes.DTO.Login.Response;
|
||||
|
||||
namespace PyroFetes.Endpoints.Login;
|
||||
|
||||
public class GetLoginRequest
|
||||
{
|
||||
public int Id { get; set; }
|
||||
}
|
||||
|
||||
public class GetLoginEndpoint(PyroFetesDbContext database) : Endpoint<GetLoginRequest, GetLoginDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/logins/{@Id}", x => new {x.Id});
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetLoginRequest req, CancellationToken ct)
|
||||
{
|
||||
Models.User? login = await database.Users
|
||||
.SingleOrDefaultAsync(x => x.Id == req.Id, ct);
|
||||
|
||||
if (login == null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
GetLoginDto responseDto = new()
|
||||
{
|
||||
Id = login.Id,
|
||||
Name = login.Name,
|
||||
Fonction = login.Fonction
|
||||
};
|
||||
|
||||
await Send.OkAsync(responseDto, ct);
|
||||
}
|
||||
}
|
||||
43
PyroFetes/Endpoints/Login/UpdateLoginEndpoint.cs
Normal file
43
PyroFetes/Endpoints/Login/UpdateLoginEndpoint.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using FastEndpoints;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PasswordGenerator;
|
||||
using PyroFetes.DTO.Login.Request;
|
||||
using PyroFetes.DTO.Login.Response;
|
||||
|
||||
namespace PyroFetes.Endpoints.Login;
|
||||
|
||||
public class UpdateLoginEndpoint(PyroFetesDbContext database) : Endpoint<UpdateLoginDto, GetLoginDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Put("/logins/{@Id}", x => new {x.Id});
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateLoginDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? login = await database.Users.SingleOrDefaultAsync(x => x.Id == req.Id, ct);
|
||||
|
||||
if (login == null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
string? salt = new Password().IncludeLowercase().IncludeUppercase().IncludeNumeric().LengthRequired(24).Next();
|
||||
|
||||
login.Name = req.Name;
|
||||
login.Password = BCrypt.Net.BCrypt.HashPassword(req.Password + salt);
|
||||
login.Salt = salt;
|
||||
await database.SaveChangesAsync(ct);
|
||||
|
||||
GetLoginDto responseDto = new()
|
||||
{
|
||||
Id = login.Id,
|
||||
Name = login.Name,
|
||||
Fonction = login.Fonction
|
||||
};
|
||||
|
||||
await Send.OkAsync(responseDto, ct);
|
||||
}
|
||||
}
|
||||
48
PyroFetes/Endpoints/Login/UserLoginEndpoint.cs
Normal file
48
PyroFetes/Endpoints/Login/UserLoginEndpoint.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using FastEndpoints;
|
||||
using FastEndpoints.Security;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PyroFetes.DTO.Login.Request;
|
||||
using PyroFetes.DTO.Login.Response;
|
||||
|
||||
namespace PyroFetes.Endpoints.Login;
|
||||
|
||||
public class UserLoginEndpoint(PyroFetesDbContext database) : Endpoint<ConnectLoginDto, GetLoginConnectDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/login");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(ConnectLoginDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? login = await database.Users.SingleOrDefaultAsync(x => x.Name == req.Name, ct);
|
||||
|
||||
if (login == null)
|
||||
{
|
||||
await Send.UnauthorizedAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
if (BCrypt.Net.BCrypt.Verify(req.Password + login.Salt, login.Password))
|
||||
{
|
||||
string jwtToken = JwtBearer.CreateToken(
|
||||
o =>
|
||||
{
|
||||
o.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong";
|
||||
o.ExpireAt = DateTime.UtcNow.AddMinutes(15);
|
||||
if (login.Fonction != null) o.User.Roles.Add(login.Fonction);
|
||||
o.User.Claims.Add(("Username", login.Name)!);
|
||||
o.User["UserId"] = "001";
|
||||
});
|
||||
|
||||
GetLoginConnectDto responseDto = new()
|
||||
{
|
||||
Token = jwtToken
|
||||
};
|
||||
|
||||
await Send.OkAsync(responseDto, ct);
|
||||
}
|
||||
else await Send.UnauthorizedAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ public class CreateMaterialEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/materials");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateMaterialDto req, CancellationToken ct)
|
||||
|
||||
@@ -11,7 +11,6 @@ public class DeleteMaterialEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/materials/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteMaterialRequest req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class GetAllMaterialsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : En
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/materials");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
|
||||
@@ -14,7 +14,6 @@ public class GetMaterialEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoi
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/materials/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetMaterialRequest req, CancellationToken ct)
|
||||
|
||||
@@ -10,7 +10,6 @@ public class UpdateMaterialEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
||||
public override void Configure()
|
||||
{
|
||||
Put("/materials/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateMaterialDto req, CancellationToken ct)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using API.DTO.Movement.Request;
|
||||
using API.DTO.Movement.Response;
|
||||
using FastEndpoints;
|
||||
using PyroFetes.DTO.Movement.Request;
|
||||
|
||||
namespace PyroFetes.Endpoints.Movement;
|
||||
|
||||
@@ -9,7 +10,6 @@ public class CreateMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/movements");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateMovementDto req, CancellationToken ct)
|
||||
@@ -18,9 +18,11 @@ public class CreateMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
||||
Models.Movement movement = new ()
|
||||
{
|
||||
Date = req.Date,
|
||||
ProductId = req.ProductId,
|
||||
Start = req.Start,
|
||||
Arrival = req.Arrival,
|
||||
Quantity = req.Quantity
|
||||
Quantity = req.Quantity,
|
||||
Type = req.Type,
|
||||
};
|
||||
|
||||
pyrofetesdbcontext.Movements.Add(movement);
|
||||
|
||||
@@ -13,7 +13,6 @@ public class DeleteMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/Movements/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteMovementRequest req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class GetAllMovementsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : En
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/movements");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
|
||||
@@ -14,7 +14,6 @@ public class GetMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) :Endpoin
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/movements/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetMovementRequest req, CancellationToken ct)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class UpdateMovementEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
||||
public override void Configure()
|
||||
{
|
||||
Put("/movements");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateMovementDto req, CancellationToken ct)
|
||||
|
||||
@@ -12,7 +12,6 @@ public class CreateProductEndpoint(PyroFetesDbContext db)
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/products");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateProductDto req, CancellationToken ct)
|
||||
@@ -29,7 +28,7 @@ public class CreateProductEndpoint(PyroFetesDbContext db)
|
||||
Image = req.Image!,
|
||||
Link = req.Link!,
|
||||
ProductCategoryId = req.ProductCategoryId,
|
||||
ClassificationId = req.ClassificationId
|
||||
ClassificationId = req.ClassificationId,
|
||||
};
|
||||
|
||||
db.Products.Add(product);
|
||||
|
||||
@@ -14,7 +14,6 @@ public class DeleteProductEndpoint(PyroFetesDbContext db) : Endpoint<DeleteProdu
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/products/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteProductRequest req, CancellationToken ct)
|
||||
|
||||
@@ -12,7 +12,6 @@ public class GetAllProductsEndpoint(PyroFetesDbContext db)
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/products");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
|
||||
@@ -17,7 +17,6 @@ public class GetProductEndpoint(PyroFetesDbContext db)
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/products/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
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
|
||||
var product = await db.Products
|
||||
.Include(p => p.Prices)
|
||||
.Include(p => p.WarehouseProducts)
|
||||
.Include(p => p.WarehouseProducts)!
|
||||
.ThenInclude(wp => wp.Warehouse)
|
||||
.SingleOrDefaultAsync(p => p.Id == req.Id, ct);
|
||||
|
||||
|
||||
@@ -6,36 +6,29 @@ using PyroFetes.Models;
|
||||
|
||||
namespace PyroFetes.Endpoints.Product;
|
||||
|
||||
// Endpoint permettant de mettre à jour un produit existant
|
||||
public class UpdateProductEndpoint(PyroFetesDbContext db)
|
||||
: Endpoint<UpdateProductDto, GetProductDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
// Route HTTP PUT avec un paramètre d'identifiant dans l'URL
|
||||
Put("/products/{@id}", x => new { x.Id });
|
||||
|
||||
// Autorise les requêtes anonymes (sans authentification)
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
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
|
||||
.Include(p => p.Prices)
|
||||
.Include(p => p.WarehouseProducts)
|
||||
.SingleOrDefaultAsync(p => p.Id == req.Id, ct);
|
||||
|
||||
// Si le produit n'existe pas, on retourne une réponse 404
|
||||
if (product is null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
// Mise à jour des propriétés principales du produit
|
||||
product.Reference = req.Reference; // Converti int → string
|
||||
product.Reference = req.Reference;
|
||||
product.Name = req.Name;
|
||||
product.Duration = req.Duration;
|
||||
product.Caliber = req.Caliber;
|
||||
@@ -47,7 +40,6 @@ public class UpdateProductEndpoint(PyroFetesDbContext db)
|
||||
product.ClassificationId = req.ClassificationId;
|
||||
product.ProductCategoryId = req.ProductCategoryId;
|
||||
|
||||
// Mise à jour des prix fournisseurs associés
|
||||
db.Prices.RemoveRange(product.Prices);
|
||||
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);
|
||||
foreach (var w in req.Warehouses)
|
||||
{
|
||||
@@ -73,18 +64,16 @@ public class UpdateProductEndpoint(PyroFetesDbContext db)
|
||||
|
||||
await db.SaveChangesAsync(ct);
|
||||
|
||||
// Construction de la réponse renvoyée au client
|
||||
var response = new GetProductDto
|
||||
{
|
||||
Id = product.Id,
|
||||
Reference = req.Reference, // DTO garde int pour cohérence
|
||||
Reference = req.Reference,
|
||||
Name = req.Name,
|
||||
Duration = req.Duration,
|
||||
Caliber = req.Caliber,
|
||||
ApprovalNumber = req.ApprovalNumber,
|
||||
Weight = req.Weight,
|
||||
Nec = req.Nec,
|
||||
// Le prix de vente est pris depuis Prices
|
||||
SellingPrice = req.Suppliers.FirstOrDefault()?.SellingPrice ?? 0,
|
||||
Image = req.Image,
|
||||
Link = req.Link,
|
||||
|
||||
@@ -9,7 +9,6 @@ public class CreateProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/productcategories");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateProductCategoryDto req, CancellationToken ct)
|
||||
|
||||
@@ -13,7 +13,6 @@ public class DeleteProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/productcategories/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteProductCategoryRequest req, CancellationToken ct)
|
||||
|
||||
@@ -4,12 +4,11 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace PyroFetes.Endpoints.ProductCategory;
|
||||
|
||||
public class GetAllProductCategoriesEndpoint(PyroFetesDbContext pyrofetesdbcontext) : EndpointWithoutRequest<List<GetProductCategoryDto>>
|
||||
public class GetAllProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext) : EndpointWithoutRequest<List<GetProductCategoryDto>>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/productcategories");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
@@ -15,7 +15,6 @@ public class GetProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext) :
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/productcategory/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetProductCategoryRequest req, CancellationToken ct)
|
||||
|
||||
@@ -10,7 +10,6 @@ public class UpdateProductCategoryEndpoint(PyroFetesDbContext pyrofetesdbcontext
|
||||
public override void Configure()
|
||||
{
|
||||
Put("/productcategory/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ public class CreateSupplierEndpoint(PyroFetesDbContext pyrofetesdbcontext)
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/suppliers");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateSupplierDto req, CancellationToken ct)
|
||||
|
||||
@@ -14,7 +14,6 @@ public class DeleteSupplierEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/suppliers/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteSupplierRequest req, CancellationToken ct)
|
||||
|
||||
@@ -12,7 +12,6 @@ public class GetAllSuppliersEndpoint(PyroFetesDbContext pyrofetesdbcontext)
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/suppliers");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
|
||||
@@ -16,7 +16,6 @@ public class GetSupplierEndpoint(PyroFetesDbContext pyrofetesdbcontext)
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/suppliers/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetSupplierRequest req, CancellationToken ct)
|
||||
|
||||
@@ -11,7 +11,6 @@ public class UpdateSupplierEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
|
||||
public override void Configure()
|
||||
{
|
||||
Put("/suppliers/{@id}", x => new { x.Id });
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateSupplierDto req, CancellationToken ct)
|
||||
|
||||
@@ -11,7 +11,6 @@ public class CreateWarehouseEndpoint(PyroFetesDbContext db)
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/warehouse");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateWarehouseDto req, CancellationToken ct)
|
||||
|
||||
@@ -14,7 +14,6 @@ public class DeleteWarehouseEndpoint(PyroFetesDbContext db) : Endpoint<DeleteWar
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/warehouse/{id}");
|
||||
AllowAnonymous();
|
||||
}
|
||||
public override async Task HandleAsync(DeleteWarehouseRequest req, CancellationToken ct)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,6 @@ public class GetAllWarehouseEndpoint(PyroFetesDbContext db)
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/warehouses");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
|
||||
@@ -17,7 +17,6 @@ public class GetWarehouseEndpoint(PyroFetesDbContext db)
|
||||
{
|
||||
// Pas de "@id" ici, juste {id}
|
||||
Get("/warehouses/{Id}");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetWarehouseRequest req, CancellationToken ct)
|
||||
|
||||
@@ -13,7 +13,6 @@ public class UpdateWarehouseEndpoint(PyroFetesDbContext db)
|
||||
{
|
||||
// Utilise {id} plutôt que {@id}
|
||||
Put("/warehouses/{Id}");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateWarehouseDto req, CancellationToken ct)
|
||||
|
||||
@@ -2,18 +2,42 @@
|
||||
|
||||
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
|
||||
{
|
||||
[Key] public int Id { get; set; }
|
||||
[Required] public DateTime Date { get; set; }
|
||||
[Required] public DateTime Start {get; set;}
|
||||
[Required] public DateTime Arrival {get; set;}
|
||||
[Required] public int Quantity {get; set;}
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public List<Product>? Products { get; set; }
|
||||
[Required]
|
||||
public DateTime Date { get; set; } = DateTime.Now;
|
||||
|
||||
public int? SourceWarehouseId {get; set;}
|
||||
public Warehouse? SourceWarehouse {get; set;}
|
||||
public int? DestinationWarehouseId {get; set;}
|
||||
public Warehouse? DestinationWarehouse {get; set;}
|
||||
public DateTime Start { get; set; }
|
||||
public DateTime Arrival { get; set; }
|
||||
|
||||
[Required]
|
||||
public int Quantity { 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; }
|
||||
}
|
||||
@@ -12,9 +12,9 @@ namespace PyroFetes.Models
|
||||
[Required, MaxLength(100)] public string? ApprovalNumber { get; set; }
|
||||
[Required] public decimal Weight { get; set; }
|
||||
[Required] public decimal Nec { get; set; }
|
||||
[Required] public string? Image { get; set; }
|
||||
[Required, MaxLength(200)] public string? Link { get; set; }
|
||||
[Required] public int MinimalQuantity { get; set; }
|
||||
public string? Image { get; set; }
|
||||
[MaxLength(200)] public string? Link { get; set; }
|
||||
public int MinimalQuantity { get; set; }
|
||||
|
||||
// Relations
|
||||
[Required] public int ClassificationId { get; set; }
|
||||
@@ -23,8 +23,7 @@ namespace PyroFetes.Models
|
||||
[Required] public int ProductCategoryId { get; set; }
|
||||
public ProductCategory? ProductCategory { get; set; }
|
||||
|
||||
[Required] public int MovementId {get; set;}
|
||||
public Movement? Movement {get; set;}
|
||||
public List<Movement>? Movements { get; set; }
|
||||
|
||||
public List<ProductDelivery>? ProductDeliveries { get; set; }
|
||||
public List<Brand>? Brands { get; set; }
|
||||
@@ -36,6 +35,5 @@ namespace PyroFetes.Models
|
||||
public List<WarehouseProduct>? WarehouseProducts { get; set; }
|
||||
public List<ProductTimecode>? ProductTimecodes { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace PyroFetes.Models;
|
||||
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
using FastEndpoints;
|
||||
using FastEndpoints.Security;
|
||||
using FastEndpoints.Swagger;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PyroFetes;
|
||||
|
||||
|
||||
|
||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Services
|
||||
builder.Services
|
||||
.AddAuthenticationJwtBearer(s => s.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong")
|
||||
.AddAuthentication();
|
||||
|
||||
builder.Services.AddAuthorization();
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
options.AddDefaultPolicy(policyBuilder =>
|
||||
policyBuilder
|
||||
.WithOrigins("http://localhost:4200") // mettre le port Angular exact
|
||||
policyBuilder.WithOrigins("http://localhost:4200")
|
||||
.WithMethods("GET", "POST", "PUT", "PATCH", "DELETE")
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials()
|
||||
)
|
||||
);
|
||||
|
||||
@@ -23,20 +32,19 @@ builder.Services.AddDbContext<PyroFetesDbContext>();
|
||||
|
||||
WebApplication app = builder.Build();
|
||||
|
||||
// Middleware
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
// CORS doit être avant les endpoints
|
||||
app.UseCors();
|
||||
|
||||
// FastEndpoints et Swagger
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseFastEndpoints(options =>
|
||||
{
|
||||
options.Endpoints.RoutePrefix = "API";
|
||||
options.Endpoints.ShortNames = true;
|
||||
}).UseSwaggerGen();
|
||||
|
||||
// app.UseAuthorization();
|
||||
// app.UseAuthentication();
|
||||
|
||||
app.Run();
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RollForward>Major</RollForward>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
@@ -22,8 +23,4 @@
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Migrations\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace PyroFetes;
|
||||
|
||||
public class PyroFetesDbContext : DbContext
|
||||
{
|
||||
|
||||
|
||||
// Entities
|
||||
public DbSet<Availability> Availabilities { get; set; }
|
||||
public DbSet<Brand> Brands { get; set; }
|
||||
@@ -55,9 +57,9 @@ public class PyroFetesDbContext : DbContext
|
||||
{
|
||||
string connectionString =
|
||||
"Server=romaric-thibault.fr;" +
|
||||
"Database=PyroFetes;" +
|
||||
"User Id=pyrofetes;" +
|
||||
"Password=Crablike8-Fringe-Swimmable;" +
|
||||
"Database=PyroMana;" +
|
||||
"User Id=matheo;" +
|
||||
"Password=Onto9-Cage-Afflicted;" +
|
||||
"TrustServerCertificate=true;";
|
||||
|
||||
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**.
|
||||
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.
|
||||
> API REST de gestion des entrepôts et produits pyrotechniques, développée avec **C#**, **ASP.NET Core** et **FastEndpoints**.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Fonctionnalités principales
|
||||
## 🛠️ Stack technique
|
||||
|
||||
### 1️⃣ Suivi et réapprovisionnement des stocks
|
||||
- Définissez un **niveau minimal de stock** pour chaque produit.
|
||||
- Surveillez les **niveaux en temps réel** grâce à une interface claire.
|
||||
- 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.
|
||||
|
||||
### 2️⃣ Gestion des fournisseurs
|
||||
- Enregistrez les informations complètes des fournisseurs : nom, adresse, coordonnées, produits fournis, délais de livraison.
|
||||
- **Associez un ou plusieurs fournisseurs** à chaque produit.
|
||||
- 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é.
|
||||
| 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 |
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ Livrables prévus
|
||||
- **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.
|
||||
- **Documentation technique** : description des fonctionnalités, architecture de l’application et API.
|
||||
## 📁 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 👥 Équipe
|
||||
- **Mathys**
|
||||
- **Enzo**
|
||||
- **Cristiano**
|
||||
- **Arsène**
|
||||
## 🚀 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)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Objectif
|
||||
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.
|
||||
## ⚙️ 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.
|
||||
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