diff --git a/GrossesMitaines/GrossesMitainesAPI/Controllers/InvoiceController.cs b/GrossesMitaines/GrossesMitainesAPI/Controllers/InvoiceController.cs index 1349439..157985d 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Controllers/InvoiceController.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Controllers/InvoiceController.cs @@ -1,22 +1,181 @@ namespace GrossesMitainesAPI.Controllers; +#region Dependencies using GrossesMitainesAPI.Data; +using GrossesMitainesAPI.Models; +using GrossesMitainesAPI.Services; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.AspNet.Identity; +using System.Data; +using System.Linq; + +#endregion [EnableCors("_myAllowSpecificOrigins"), ApiController, Route("api/[controller]"), Authorize(AuthenticationSchemes = "Identity.Application", Roles = "Administrateur")] public class InvoiceController : Controller { + #region DI Fields private readonly ILogger _logger; private readonly InventoryContext _context; + private readonly DatabaseCacheService _cache; + private readonly SignInManager _signInMan; + private readonly Microsoft.AspNetCore.Identity.UserManager _userMan; - public InvoiceController(ILogger logger, InventoryContext context) { - this._logger = logger; - this._context = context; + #endregion + + #region Ctor + public InvoiceController(ILogger logger, + InventoryContext context, + DatabaseCacheService cache, + Microsoft.AspNetCore.Identity.UserManager userMan) { + _logger = logger; + _context = context; + _cache = cache; + _userMan = userMan; } + #endregion + #region API Methods + [HttpGet, Route("GetList"), Authorize(Roles = "Client, Administrateur")] + public async Task>> Get(bool? all = false) { + IList roles; + string id; + try { // Trouver les rôles de l'utilisateur, assumer non-admin si impossible à trouver. + roles = await _userMan.GetRolesAsync(await _userMan.GetUserAsync(_signInMan.Context.User)); + } catch (Exception e) { + _logger.LogError(10, e.Message); + roles = new List(); + } -} + try { + id = _signInMan.Context.User.Identity.GetUserId(); + if (all is not null && all == true && roles.Contains("Administrateur")) + return _context.Invoices.Include("LinkedAccount, ShippingAddress").ToList(); + else return _context.Invoices.Include("ShippingAddress").Where(x => x.LinkedAccount != null && + x.LinkedAccount.Id == id).ToList(); + } catch (Exception e) { + _logger.LogError(10, e.Message); + return BadRequest(); + } + } + [HttpGet, Route("Get"), Authorize(Roles = "Client, Administrateur")] + public async Task> Get(int id) { + IList roles; + InvoiceModel inv; + + try { // Trouver les rôles de l'utilisateur, assumer non-admin si impossible à trouver. + roles = await _userMan.GetRolesAsync(await _userMan.GetUserAsync(_signInMan.Context.User)); + } catch (Exception e) { + _logger.LogError(10, e.Message); + roles = new List(); + } + + try { + inv = _context.Invoices.Where(x => x.Id == id).Include("ShippingAddress").First(); + } catch (Exception e) { + _logger.LogError(10, e.Message); + return BadRequest(); + } + + if (roles.Contains("Administrateur") || + (inv.LinkedAccount is not null && + inv.LinkedAccount.Id == _signInMan.Context.User.Identity.GetUserId())) + return inv; + else return Unauthorized(); + } + + [HttpPost, AllowAnonymous] + public async Task> Post(InvoiceModel inv) { + var user = await _userMan.GetUserAsync(_signInMan.Context.User); + List prods; + + if (user is not null) + inv.LinkedAccount = user; + inv.PurchaseDate = DateTime.Now; // Pour forcer la date. + + var prodcom = inv.Products.ToList(); + + try { + prods = _context.Products.Where(x => inv.Products.Select(x => x.Product).Contains(x)).ToList(); + } catch (Exception e) { + _logger.LogError(8, e.Message); + return BadRequest(); + } + + foreach (var prod in prodcom) { // Update de quantités dans l'inventaire. + ProductModel inventProd = prods.Where(x => x.Id == prod.Product.Id).First(); + if (inventProd.Quantity > prod.Quantity) + return BadRequest(); // TODO: retourner le produit qui ne peut pas être vendu. + if (inventProd.Quantity == prod.Quantity) { + inventProd.Quantity = 0; + inventProd.Status = inventProd.Status == ProductModel.States.Clearance ? + ProductModel.States.Discontinued : + ProductModel.States.BackOrder; + } else inventProd.Quantity -= prod.Quantity; + } + + try { // Faire les updates dans la BD. + _context.Invoices.Add(inv); + _context.Products.UpdateRange(prods); + _context.SaveChanges(); + } catch (Exception e) { + _logger.LogError(8, e.Message); + return BadRequest(); + } + + _cache.askForRefresh(); + return Ok(inv); + } + + [HttpPost, Authorize(Roles = "Client, Administrateur")] + public async Task> Cancel(int id) { + InvoiceModel inv; + IList roles; + + try { // Trouver la commande. + inv = _context.Invoices.Where(x => x.Id == id) + .Include("Product").First(); + } catch (Exception e) { + _logger.LogError(8, e.Message); + return BadRequest(); + } + + try { // Trouver les rôles de l'utilisateur, assumer non-admin si impossible à trouver. + roles = await _userMan.GetRolesAsync(await _userMan.GetUserAsync(_signInMan.Context.User)); + } catch (Exception e) { + _logger.LogError(10, e.Message); + roles = new List(); + } + + // Pour ne pas pouvoir arbitrairement annuler la commande d'un autre client en tant que client. + if (!((inv.LinkedAccount is not null && + inv.LinkedAccount.Id == _signInMan.Context.User.Identity.GetUserId()) || + roles.Contains("Administrateur"))) + return Unauthorized(); + + inv.Status = InvoiceModel.InStates.Cancelled; + + foreach (var prod in inv.Products) // Revert l'inventaire. + prod.Product.Quantity = prod.Product.Quantity + prod.Quantity; + + try { + _context.Update(inv); + _context.SaveChanges(); + } catch (Exception e) { + _logger.LogError(8, e.Message); + return BadRequest(); + } + + _cache.askForRefresh(); + + return Ok(inv); + } + + #endregion +} \ No newline at end of file diff --git a/GrossesMitaines/GrossesMitainesAPI/Controllers/LoginController.cs b/GrossesMitaines/GrossesMitainesAPI/Controllers/LoginController.cs index 214fffe..06fe8bb 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Controllers/LoginController.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Controllers/LoginController.cs @@ -30,14 +30,6 @@ public class LoginController : Controller { #endregion - #region Utility Classes - public class LoginUser { - public string email { get; set; } = ""; - public string password { get; set; } = ""; - } - - #endregion - #region API Methods [HttpGet, Route("WhoAmI")] public async Task WhoAmI() { @@ -51,7 +43,7 @@ public class LoginController : Controller { } [HttpPost, Route("Login"), AllowAnonymous] - public async Task Login(LoginUser user, bool rememberMe = false) { + public async Task Login(LoginModel user, bool rememberMe = false) { var User = await _userMan.FindByEmailAsync(user.email); return await _signInMan.PasswordSignInAsync(User, user.password, rememberMe, false); } diff --git a/GrossesMitaines/GrossesMitainesAPI/Controllers/UserController.cs b/GrossesMitaines/GrossesMitainesAPI/Controllers/UserController.cs index 81df983..7ed6a19 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Controllers/UserController.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Controllers/UserController.cs @@ -1,4 +1,5 @@ using GrossesMitainesAPI.Data; +using GrossesMitainesAPI.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Identity; @@ -10,16 +11,34 @@ namespace GrossesMitainesAPI.Controllers; public class UserController : Controller { private readonly UserManager _userMan; private readonly SignInManager _signInMan; + private readonly ILogger _logger; - public UserController(SignInManager signin, UserManager userman) { - this._signInMan = signin; - this._userMan = userman; + public UserController(ILogger logger, SignInManager signin, UserManager userman) { + _logger = logger; + _signInMan = signin; + _userMan = userman; } - - - - - + [HttpPost, AllowAnonymous] + public async Task> Post(SignUpUserModel sign) { + InventoryUser usr; + try { + usr = new(sign); + } catch { + return BadRequest("Erreur utilisateur"); + } + try { + usr.PasswordHash = new PasswordHasher().HashPassword(usr, sign.Password); + } catch { + return BadRequest("Erreur de mot de passe."); + } + try { + await _userMan.CreateAsync(usr); + await _userMan.AddToRoleAsync(usr, "Client"); + } catch (Exception e) { + return BadRequest(e.Message); + } + return new ReturnUserViewModel(usr, "Client"); + } } diff --git a/GrossesMitaines/GrossesMitainesAPI/Data/InventoryUser.cs b/GrossesMitaines/GrossesMitainesAPI/Data/InventoryUser.cs index 98ad9cb..67ed060 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Data/InventoryUser.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Data/InventoryUser.cs @@ -9,5 +9,16 @@ public class InventoryUser : IdentityUser { [Required, MinLength(1), MaxLength(30)] public string LastName { get; set; } public List Adresses { get; set; } + + public InventoryUser(SignUpUserModel sign) { + FirstName = sign.FirstName; + LastName = sign.LastName; + UserName = sign.FirstName + " " + sign.LastName; + NormalizedUserName = UserName.ToUpper(); + NormalizedEmail = Email.ToUpper(); + Email = sign.Email; + PhoneNumber = sign.Phone; + Adresses = sign.Adresses; + } } diff --git a/GrossesMitaines/GrossesMitainesAPI/Models/InvoiceModel.cs b/GrossesMitaines/GrossesMitainesAPI/Models/InvoiceModel.cs index f5fb985..2cffd55 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Models/InvoiceModel.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Models/InvoiceModel.cs @@ -5,11 +5,19 @@ using System.ComponentModel.DataAnnotations.Schema; namespace GrossesMitainesAPI.Models; public class InvoiceModel { + public enum InStates { + Confirmed, + Cancelled, + Preparing, + Shipping, + Shipped, + Returned + } public class ProductInvoice { [Key] public int Id { get; set; } public ProductModel Product { get; set; } - public int Quantity { get; set; } + public uint Quantity { get; set; } } [Key] @@ -23,14 +31,11 @@ public class InvoiceModel { [Required, EmailAddress] public string EmailAddress { get; set; } public InventoryUser? LinkedAccount { get; set; } - public DateTime PurchaseDate { get; } = DateTime.Now; + public DateTime PurchaseDate { get; set; } = DateTime.Now; [Required] public List Products { get; set; } - - //[Required, Column("BillingAddress")] - //public AddressModel BillingAddress { get; set; } [Required] public AddressModel ShippingAddress { get; set; } - public bool Canceled { get; set; } = false; + public InStates Status { get; set; } = InStates.Confirmed; } diff --git a/GrossesMitaines/GrossesMitainesAPI/Models/LoginModel.cs b/GrossesMitaines/GrossesMitainesAPI/Models/LoginModel.cs new file mode 100644 index 0000000..202d525 --- /dev/null +++ b/GrossesMitaines/GrossesMitainesAPI/Models/LoginModel.cs @@ -0,0 +1,5 @@ +namespace GrossesMitainesAPI.Models; +public class LoginModel { + public string email { get; set; } = ""; + public string password { get; set; } = ""; +} diff --git a/GrossesMitaines/GrossesMitainesAPI/Models/SignUpUserModel.cs b/GrossesMitaines/GrossesMitainesAPI/Models/SignUpUserModel.cs new file mode 100644 index 0000000..f8a3763 --- /dev/null +++ b/GrossesMitaines/GrossesMitainesAPI/Models/SignUpUserModel.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace GrossesMitainesAPI.Models; +public class SignUpUserModel { + [Required, MinLength(2), MaxLength(30)] + public string FirstName { get; set; } + [Required, MinLength(1), MaxLength(30)] + public string LastName { get; set; } + [Required, EmailAddress] + public string Email { get; set; } + [Required, Phone] + public string Phone { get; set; } + [Required] + public string Password { get; set; } + public List Adresses { get; set; } +} +