diff --git a/GrossesMitaines/GrossesMitainesAPI/Controllers/InventoryController.cs b/GrossesMitaines/GrossesMitainesAPI/Controllers/InventoryController.cs index 0bc9694..065d28d 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Controllers/InventoryController.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Controllers/InventoryController.cs @@ -5,6 +5,7 @@ using GrossesMitainesAPI.Data; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Cors; using GrossesMitainesAPI.Services; +using Microsoft.AspNetCore.Authorization; namespace GrossesMitainesAPI.Controllers; @@ -22,7 +23,7 @@ public class InventoryController : Controller { _cache = cache; } - [EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Inventory")] // Pour faire des calls async par paquet de AMOUNT (5) (pour du loading en scrollant) + [EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Inventory"), AllowAnonymous] // Pour faire des calls async par paquet de AMOUNT (5) (pour du loading en scrollant) public IEnumerable Get(int? lastId, string? order, string? filterPrice, string? filterState, bool? all) { bool islock = false; IQueryable ret; @@ -127,7 +128,7 @@ public class InventoryController : Controller { } } // Inventory/Delete => Décrémenter un produit. Va aller chercher directement dans la BD. - [EnableCors("_myAllowSpecificOrigins"), HttpDelete(Name = "Inventory")] + [EnableCors("_myAllowSpecificOrigins"), HttpDelete(Name = "Inventory"), AllowAnonymous] public ActionResult Delete(int? id) { int rid = 0; if (!id.HasValue) { @@ -139,6 +140,8 @@ public class InventoryController : Controller { rid = prod.Id; if (prod.Quantity > 0) { prod.Quantity = prod.Quantity - 1; + prod.Sales = prod.Sales + 1; + prod.LastSale = DateTime.Now; if (prod.Quantity == 0) prod.Status = prod.Status == Product.States.Clearance? Product.States.Discontinued: diff --git a/GrossesMitaines/GrossesMitainesAPI/Controllers/ProductController.cs b/GrossesMitaines/GrossesMitainesAPI/Controllers/ProductController.cs index 57e08d8..01e36d0 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Controllers/ProductController.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Controllers/ProductController.cs @@ -29,7 +29,7 @@ public class ProductController : ControllerBase { } [EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Product"), AllowAnonymous] - public ActionResult Get(int id) { + public ActionResult Get(int id) { Product prod; try { prod = _context.Products.Where(x => x.Id == id).First(); @@ -38,7 +38,8 @@ public class ProductController : ControllerBase { _logger.LogError(8, e.Message); return NotFound(); } - return prod; + _cache.addHit((uint)id); + return new ProductViewModel(prod); } [EnableCors("_myAllowSpecificOrigins"), HttpPost(Name = "Product")] diff --git a/GrossesMitaines/GrossesMitainesAPI/Controllers/SearchController.cs b/GrossesMitaines/GrossesMitainesAPI/Controllers/SearchController.cs index 38a7243..f94c71e 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Controllers/SearchController.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Controllers/SearchController.cs @@ -26,14 +26,14 @@ public class SearchController : Controller { _searchCache = _cache.GetCacheCopy(); } - [EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Search")] + [EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Search"), AllowAnonymous] public IEnumerable Get(string query, bool? preview, bool? deep) { if (_searchCache is not null) return SearchCached(query, preview, deep); - else return Search(query, preview, deep); + else return SearchDirect(query, preview, deep); } - private List Search(string query, bool? preview, bool? deep) { + private List SearchDirect(string query, bool? preview, bool? deep) { List products = new(); query = query.Trim(); try { // Pour faire une liste priorisée. @@ -80,7 +80,7 @@ public class SearchController : Controller { query = query.Trim(); if (_searchCache is null) { _logger.LogError(8, "Erreur de cache."); - return Search(query, preview, deep); // Fallback vers version non-cached en cas d'erreur. + return SearchDirect(query, preview, deep); // Fallback vers version non-cached en cas d'erreur. } try { // Pour faire une liste priorisée. if (preview.HasValue && preview == true) @@ -117,7 +117,7 @@ public class SearchController : Controller { } } catch (Exception e) { _logger.LogError(8, e.Message); - return Search(query, preview, deep); // Fallback vers version non-cached en cas d'erreur. + return SearchDirect(query, preview, deep); // Fallback vers version non-cached en cas d'erreur. } return products; } diff --git a/GrossesMitaines/GrossesMitainesAPI/Migrations/20221025170101_Initial-Db.Designer.cs b/GrossesMitaines/GrossesMitainesAPI/Migrations/20221027160052_Initial-Db.Designer.cs similarity index 86% rename from GrossesMitaines/GrossesMitainesAPI/Migrations/20221025170101_Initial-Db.Designer.cs rename to GrossesMitaines/GrossesMitainesAPI/Migrations/20221027160052_Initial-Db.Designer.cs index 592204a..0ebfbe0 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Migrations/20221025170101_Initial-Db.Designer.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Migrations/20221027160052_Initial-Db.Designer.cs @@ -1,4 +1,5 @@ // +using System; using GrossesMitainesAPI.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -11,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace GrossesMitainesAPI.Migrations { [DbContext(typeof(InventoryContext))] - [Migration("20221025170101_Initial-Db")] + [Migration("20221027160052_Initial-Db")] partial class InitialDb { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -39,9 +40,18 @@ namespace GrossesMitainesAPI.Migrations .IsRequired() .HasColumnType("nvarchar(max)"); + b.Property("Hits") + .HasColumnType("bigint"); + b.Property("ImageName") .HasColumnType("nvarchar(max)"); + b.Property("LastHit") + .HasColumnType("datetime2"); + + b.Property("LastSale") + .HasColumnType("datetime2"); + b.Property("Price") .HasColumnType("decimal(18,2)"); @@ -51,6 +61,9 @@ namespace GrossesMitainesAPI.Migrations b.Property("Quantity") .HasColumnType("bigint"); + b.Property("Sales") + .HasColumnType("bigint"); + b.Property("Status") .HasColumnType("int"); @@ -69,10 +82,12 @@ namespace GrossesMitainesAPI.Migrations Id = 1, Category = "Linge", Description = "Pour faire votre propre bonhomme de 1837, comme dans le bon vieux temps.", + Hits = 0L, ImageName = "ceintureflechee", Price = 85.86m, PromoPrice = 29.99m, Quantity = 1L, + Sales = 0L, Status = 4, Title = "Ceinture flèchée" }, @@ -81,10 +96,12 @@ namespace GrossesMitainesAPI.Migrations Id = 2, Category = "Linge", Description = "Parce que ça sent la coupe!", + Hits = 0L, ImageName = "pantouflesCH", Price = 15.64m, PromoPrice = 9.99m, Quantity = 54L, + Sales = 0L, Status = 0, Title = "Pantoufles du Canadien en Phentex" }, @@ -93,10 +110,12 @@ namespace GrossesMitainesAPI.Migrations Id = 3, Category = "Homme", Description = "On ne lui ferait pas mal, en tout cas!!", + Hits = 0L, ImageName = "jeanlucmongrain", Price = 1453.12m, PromoPrice = 999.99m, Quantity = 1L, + Sales = 0L, Status = 3, Title = "Jean-Luc Mongrain" }, @@ -105,10 +124,12 @@ namespace GrossesMitainesAPI.Migrations Id = 4, Category = "Linge", Description = "Tellement simple et comfortable.", + Hits = 0L, ImageName = "tshirt", Price = 12.12m, PromoPrice = 9.99m, Quantity = 143L, + Sales = 0L, Status = 0, Title = "T-Shirt" }, @@ -117,10 +138,12 @@ namespace GrossesMitainesAPI.Migrations Id = 5, Category = "Vêtement d'extérieur", Description = "Deux pour un!", + Hits = 0L, ImageName = "mitaines", Price = 8.18m, PromoPrice = 6.99m, Quantity = 1423L, + Sales = 0L, Status = 0, Title = "Mitaines" }, @@ -129,10 +152,12 @@ namespace GrossesMitainesAPI.Migrations Id = 6, Category = "Vêtement d'extérieur", Description = "Deux pour un!", + Hits = 0L, ImageName = "foulard", Price = 10.56m, PromoPrice = 8.99m, Quantity = 14L, + Sales = 0L, Status = 4, Title = "Foulard" }, @@ -141,10 +166,12 @@ namespace GrossesMitainesAPI.Migrations Id = 7, Category = "Sous-Vêtement", Description = "Pour garder le p'tit bout au chaud.", + Hits = 0L, ImageName = "kokin", Price = 15.45m, PromoPrice = 12.99m, Quantity = 144L, + Sales = 0L, Status = 4, Title = "Jock-Strap en phentex" }, @@ -153,10 +180,12 @@ namespace GrossesMitainesAPI.Migrations Id = 8, Category = "Sous-Vêtement", Description = "Pour garder l'absence de p'tit bout au chaud.", + Hits = 0L, ImageName = "kokin", Price = 15.45m, PromoPrice = 12.99m, Quantity = 224L, + Sales = 0L, Status = 4, Title = "Jock-Strap féminin en phentex" }, @@ -165,10 +194,12 @@ namespace GrossesMitainesAPI.Migrations Id = 9, Category = "Alien", Description = "En chiffon.", + Hits = 0L, ImageName = "bibi", Price = 1045.45m, PromoPrice = 1023.99m, Quantity = 1L, + Sales = 0L, Status = 3, Title = "Bibi" }, @@ -177,10 +208,12 @@ namespace GrossesMitainesAPI.Migrations Id = 10, Category = "Vêtement d'extérieur", Description = "En chiffon.", + Hits = 0L, ImageName = "tuque", Price = 15.45m, PromoPrice = 12.99m, Quantity = 1L, + Sales = 0L, Status = 0, Title = "Tuque en laine" }, @@ -189,10 +222,12 @@ namespace GrossesMitainesAPI.Migrations Id = 11, Category = "Vêtement d'extérieur", Description = "Pour se faire taper dessus avec une poêle à frire tout en restant au chaud.", + Hits = 0L, ImageName = "bonhomme", Price = 145.45m, PromoPrice = 123.99m, Quantity = 1L, + Sales = 0L, Status = 4, Title = "Habit de Bonhomme Carnaval" }, @@ -201,10 +236,12 @@ namespace GrossesMitainesAPI.Migrations Id = 12, Category = "Autre", Description = "Pour se pêter la fiole avec style.", + Hits = 0L, ImageName = "gauze", Price = 145.45m, PromoPrice = 123.99m, Quantity = 0L, + Sales = 0L, Status = 1, Title = "Gauze en phentex" }, @@ -213,10 +250,12 @@ namespace GrossesMitainesAPI.Migrations Id = 13, Category = "Homme", Description = "En chiffon.", + Hits = 0L, ImageName = "jesus", Price = 145.45m, PromoPrice = 123.99m, Quantity = 1L, + Sales = 0L, Status = 3, Title = "Petit Jésus de plâtre" }, @@ -225,10 +264,12 @@ namespace GrossesMitainesAPI.Migrations Id = 14, Category = "Autre", Description = "À écouter dans l'habit de Bonhomme Carnaval tant que possible.", + Hits = 0L, ImageName = "vhs", Price = 3.45m, PromoPrice = 1.99m, Quantity = 164363L, + Sales = 0L, Status = 3, Title = "VHS de la Guerre des Tuques" }, @@ -237,10 +278,12 @@ namespace GrossesMitainesAPI.Migrations Id = 15, Category = "Linge", Description = "(N'est pas réellement pare-balle).", + Hits = 0L, ImageName = "chandailquetaine", Price = 1435.45m, PromoPrice = 1223.99m, Quantity = 18L, + Sales = 0L, Status = 3, Title = "Gilet pare-balle en laine" }, @@ -249,10 +292,12 @@ namespace GrossesMitainesAPI.Migrations Id = 16, Category = "Autre", Description = "Pour s'éffoirer le nez dedans.", + Hits = 0L, ImageName = "doudou", Price = 14.45m, PromoPrice = 13.99m, Quantity = 14L, + Sales = 0L, Status = 0, Title = "Doudou" }, @@ -261,10 +306,12 @@ namespace GrossesMitainesAPI.Migrations Id = 17, Category = "Vêtements d'extérieur", Description = "Pour avoir l'air thug en hiver.", + Hits = 0L, ImageName = "mitaines2", Price = 9.45m, PromoPrice = 8.99m, Quantity = 16L, + Sales = 0L, Status = 0, Title = "Mitaines pas de doigts" }); diff --git a/GrossesMitaines/GrossesMitainesAPI/Migrations/20221025170101_Initial-Db.cs b/GrossesMitaines/GrossesMitainesAPI/Migrations/20221027160052_Initial-Db.cs similarity index 55% rename from GrossesMitaines/GrossesMitainesAPI/Migrations/20221025170101_Initial-Db.cs rename to GrossesMitaines/GrossesMitainesAPI/Migrations/20221027160052_Initial-Db.cs index 21692ba..58fda50 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Migrations/20221025170101_Initial-Db.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Migrations/20221027160052_Initial-Db.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore.Migrations; +using System; +using Microsoft.EntityFrameworkCore.Migrations; #nullable disable @@ -21,6 +22,10 @@ namespace GrossesMitainesAPI.Migrations PromoPrice = table.Column(type: "decimal(18,2)", nullable: false), Quantity = table.Column(type: "bigint", nullable: false), Status = table.Column(type: "int", nullable: false), + Hits = table.Column(type: "bigint", nullable: false), + Sales = table.Column(type: "bigint", nullable: false), + LastSale = table.Column(type: "datetime2", nullable: true), + LastHit = table.Column(type: "datetime2", nullable: true), ImageName = table.Column(type: "nvarchar(max)", nullable: true) }, constraints: table => @@ -30,26 +35,26 @@ namespace GrossesMitainesAPI.Migrations migrationBuilder.InsertData( table: "Products", - columns: new[] { "Id", "Category", "Description", "ImageName", "Price", "PromoPrice", "Quantity", "Status", "Title" }, + columns: new[] { "Id", "Category", "Description", "Hits", "ImageName", "LastHit", "LastSale", "Price", "PromoPrice", "Quantity", "Sales", "Status", "Title" }, values: new object[,] { - { 1, "Linge", "Pour faire votre propre bonhomme de 1837, comme dans le bon vieux temps.", "ceintureflechee", 85.86m, 29.99m, 1L, 4, "Ceinture flèchée" }, - { 2, "Linge", "Parce que ça sent la coupe!", "pantouflesCH", 15.64m, 9.99m, 54L, 0, "Pantoufles du Canadien en Phentex" }, - { 3, "Homme", "On ne lui ferait pas mal, en tout cas!!", "jeanlucmongrain", 1453.12m, 999.99m, 1L, 3, "Jean-Luc Mongrain" }, - { 4, "Linge", "Tellement simple et comfortable.", "tshirt", 12.12m, 9.99m, 143L, 0, "T-Shirt" }, - { 5, "Vêtement d'extérieur", "Deux pour un!", "mitaines", 8.18m, 6.99m, 1423L, 0, "Mitaines" }, - { 6, "Vêtement d'extérieur", "Deux pour un!", "foulard", 10.56m, 8.99m, 14L, 4, "Foulard" }, - { 7, "Sous-Vêtement", "Pour garder le p'tit bout au chaud.", "kokin", 15.45m, 12.99m, 144L, 4, "Jock-Strap en phentex" }, - { 8, "Sous-Vêtement", "Pour garder l'absence de p'tit bout au chaud.", "kokin", 15.45m, 12.99m, 224L, 4, "Jock-Strap féminin en phentex" }, - { 9, "Alien", "En chiffon.", "bibi", 1045.45m, 1023.99m, 1L, 3, "Bibi" }, - { 10, "Vêtement d'extérieur", "En chiffon.", "tuque", 15.45m, 12.99m, 1L, 0, "Tuque en laine" }, - { 11, "Vêtement d'extérieur", "Pour se faire taper dessus avec une poêle à frire tout en restant au chaud.", "bonhomme", 145.45m, 123.99m, 1L, 4, "Habit de Bonhomme Carnaval" }, - { 12, "Autre", "Pour se pêter la fiole avec style.", "gauze", 145.45m, 123.99m, 0L, 1, "Gauze en phentex" }, - { 13, "Homme", "En chiffon.", "jesus", 145.45m, 123.99m, 1L, 3, "Petit Jésus de plâtre" }, - { 14, "Autre", "À écouter dans l'habit de Bonhomme Carnaval tant que possible.", "vhs", 3.45m, 1.99m, 164363L, 3, "VHS de la Guerre des Tuques" }, - { 15, "Linge", "(N'est pas réellement pare-balle).", "chandailquetaine", 1435.45m, 1223.99m, 18L, 3, "Gilet pare-balle en laine" }, - { 16, "Autre", "Pour s'éffoirer le nez dedans.", "doudou", 14.45m, 13.99m, 14L, 0, "Doudou" }, - { 17, "Vêtements d'extérieur", "Pour avoir l'air thug en hiver.", "mitaines2", 9.45m, 8.99m, 16L, 0, "Mitaines pas de doigts" } + { 1, "Linge", "Pour faire votre propre bonhomme de 1837, comme dans le bon vieux temps.", 0L, "ceintureflechee", null, null, 85.86m, 29.99m, 1L, 0L, 4, "Ceinture flèchée" }, + { 2, "Linge", "Parce que ça sent la coupe!", 0L, "pantouflesCH", null, null, 15.64m, 9.99m, 54L, 0L, 0, "Pantoufles du Canadien en Phentex" }, + { 3, "Homme", "On ne lui ferait pas mal, en tout cas!!", 0L, "jeanlucmongrain", null, null, 1453.12m, 999.99m, 1L, 0L, 3, "Jean-Luc Mongrain" }, + { 4, "Linge", "Tellement simple et comfortable.", 0L, "tshirt", null, null, 12.12m, 9.99m, 143L, 0L, 0, "T-Shirt" }, + { 5, "Vêtement d'extérieur", "Deux pour un!", 0L, "mitaines", null, null, 8.18m, 6.99m, 1423L, 0L, 0, "Mitaines" }, + { 6, "Vêtement d'extérieur", "Deux pour un!", 0L, "foulard", null, null, 10.56m, 8.99m, 14L, 0L, 4, "Foulard" }, + { 7, "Sous-Vêtement", "Pour garder le p'tit bout au chaud.", 0L, "kokin", null, null, 15.45m, 12.99m, 144L, 0L, 4, "Jock-Strap en phentex" }, + { 8, "Sous-Vêtement", "Pour garder l'absence de p'tit bout au chaud.", 0L, "kokin", null, null, 15.45m, 12.99m, 224L, 0L, 4, "Jock-Strap féminin en phentex" }, + { 9, "Alien", "En chiffon.", 0L, "bibi", null, null, 1045.45m, 1023.99m, 1L, 0L, 3, "Bibi" }, + { 10, "Vêtement d'extérieur", "En chiffon.", 0L, "tuque", null, null, 15.45m, 12.99m, 1L, 0L, 0, "Tuque en laine" }, + { 11, "Vêtement d'extérieur", "Pour se faire taper dessus avec une poêle à frire tout en restant au chaud.", 0L, "bonhomme", null, null, 145.45m, 123.99m, 1L, 0L, 4, "Habit de Bonhomme Carnaval" }, + { 12, "Autre", "Pour se pêter la fiole avec style.", 0L, "gauze", null, null, 145.45m, 123.99m, 0L, 0L, 1, "Gauze en phentex" }, + { 13, "Homme", "En chiffon.", 0L, "jesus", null, null, 145.45m, 123.99m, 1L, 0L, 3, "Petit Jésus de plâtre" }, + { 14, "Autre", "À écouter dans l'habit de Bonhomme Carnaval tant que possible.", 0L, "vhs", null, null, 3.45m, 1.99m, 164363L, 0L, 3, "VHS de la Guerre des Tuques" }, + { 15, "Linge", "(N'est pas réellement pare-balle).", 0L, "chandailquetaine", null, null, 1435.45m, 1223.99m, 18L, 0L, 3, "Gilet pare-balle en laine" }, + { 16, "Autre", "Pour s'éffoirer le nez dedans.", 0L, "doudou", null, null, 14.45m, 13.99m, 14L, 0L, 0, "Doudou" }, + { 17, "Vêtements d'extérieur", "Pour avoir l'air thug en hiver.", 0L, "mitaines2", null, null, 9.45m, 8.99m, 16L, 0L, 0, "Mitaines pas de doigts" } }); } diff --git a/GrossesMitaines/GrossesMitainesAPI/Migrations/InventoryContextModelSnapshot.cs b/GrossesMitaines/GrossesMitainesAPI/Migrations/InventoryContextModelSnapshot.cs index 23c3885..bfc923b 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Migrations/InventoryContextModelSnapshot.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Migrations/InventoryContextModelSnapshot.cs @@ -1,4 +1,5 @@ // +using System; using GrossesMitainesAPI.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -37,9 +38,18 @@ namespace GrossesMitainesAPI.Migrations .IsRequired() .HasColumnType("nvarchar(max)"); + b.Property("Hits") + .HasColumnType("bigint"); + b.Property("ImageName") .HasColumnType("nvarchar(max)"); + b.Property("LastHit") + .HasColumnType("datetime2"); + + b.Property("LastSale") + .HasColumnType("datetime2"); + b.Property("Price") .HasColumnType("decimal(18,2)"); @@ -49,6 +59,9 @@ namespace GrossesMitainesAPI.Migrations b.Property("Quantity") .HasColumnType("bigint"); + b.Property("Sales") + .HasColumnType("bigint"); + b.Property("Status") .HasColumnType("int"); @@ -67,10 +80,12 @@ namespace GrossesMitainesAPI.Migrations Id = 1, Category = "Linge", Description = "Pour faire votre propre bonhomme de 1837, comme dans le bon vieux temps.", + Hits = 0L, ImageName = "ceintureflechee", Price = 85.86m, PromoPrice = 29.99m, Quantity = 1L, + Sales = 0L, Status = 4, Title = "Ceinture flèchée" }, @@ -79,10 +94,12 @@ namespace GrossesMitainesAPI.Migrations Id = 2, Category = "Linge", Description = "Parce que ça sent la coupe!", + Hits = 0L, ImageName = "pantouflesCH", Price = 15.64m, PromoPrice = 9.99m, Quantity = 54L, + Sales = 0L, Status = 0, Title = "Pantoufles du Canadien en Phentex" }, @@ -91,10 +108,12 @@ namespace GrossesMitainesAPI.Migrations Id = 3, Category = "Homme", Description = "On ne lui ferait pas mal, en tout cas!!", + Hits = 0L, ImageName = "jeanlucmongrain", Price = 1453.12m, PromoPrice = 999.99m, Quantity = 1L, + Sales = 0L, Status = 3, Title = "Jean-Luc Mongrain" }, @@ -103,10 +122,12 @@ namespace GrossesMitainesAPI.Migrations Id = 4, Category = "Linge", Description = "Tellement simple et comfortable.", + Hits = 0L, ImageName = "tshirt", Price = 12.12m, PromoPrice = 9.99m, Quantity = 143L, + Sales = 0L, Status = 0, Title = "T-Shirt" }, @@ -115,10 +136,12 @@ namespace GrossesMitainesAPI.Migrations Id = 5, Category = "Vêtement d'extérieur", Description = "Deux pour un!", + Hits = 0L, ImageName = "mitaines", Price = 8.18m, PromoPrice = 6.99m, Quantity = 1423L, + Sales = 0L, Status = 0, Title = "Mitaines" }, @@ -127,10 +150,12 @@ namespace GrossesMitainesAPI.Migrations Id = 6, Category = "Vêtement d'extérieur", Description = "Deux pour un!", + Hits = 0L, ImageName = "foulard", Price = 10.56m, PromoPrice = 8.99m, Quantity = 14L, + Sales = 0L, Status = 4, Title = "Foulard" }, @@ -139,10 +164,12 @@ namespace GrossesMitainesAPI.Migrations Id = 7, Category = "Sous-Vêtement", Description = "Pour garder le p'tit bout au chaud.", + Hits = 0L, ImageName = "kokin", Price = 15.45m, PromoPrice = 12.99m, Quantity = 144L, + Sales = 0L, Status = 4, Title = "Jock-Strap en phentex" }, @@ -151,10 +178,12 @@ namespace GrossesMitainesAPI.Migrations Id = 8, Category = "Sous-Vêtement", Description = "Pour garder l'absence de p'tit bout au chaud.", + Hits = 0L, ImageName = "kokin", Price = 15.45m, PromoPrice = 12.99m, Quantity = 224L, + Sales = 0L, Status = 4, Title = "Jock-Strap féminin en phentex" }, @@ -163,10 +192,12 @@ namespace GrossesMitainesAPI.Migrations Id = 9, Category = "Alien", Description = "En chiffon.", + Hits = 0L, ImageName = "bibi", Price = 1045.45m, PromoPrice = 1023.99m, Quantity = 1L, + Sales = 0L, Status = 3, Title = "Bibi" }, @@ -175,10 +206,12 @@ namespace GrossesMitainesAPI.Migrations Id = 10, Category = "Vêtement d'extérieur", Description = "En chiffon.", + Hits = 0L, ImageName = "tuque", Price = 15.45m, PromoPrice = 12.99m, Quantity = 1L, + Sales = 0L, Status = 0, Title = "Tuque en laine" }, @@ -187,10 +220,12 @@ namespace GrossesMitainesAPI.Migrations Id = 11, Category = "Vêtement d'extérieur", Description = "Pour se faire taper dessus avec une poêle à frire tout en restant au chaud.", + Hits = 0L, ImageName = "bonhomme", Price = 145.45m, PromoPrice = 123.99m, Quantity = 1L, + Sales = 0L, Status = 4, Title = "Habit de Bonhomme Carnaval" }, @@ -199,10 +234,12 @@ namespace GrossesMitainesAPI.Migrations Id = 12, Category = "Autre", Description = "Pour se pêter la fiole avec style.", + Hits = 0L, ImageName = "gauze", Price = 145.45m, PromoPrice = 123.99m, Quantity = 0L, + Sales = 0L, Status = 1, Title = "Gauze en phentex" }, @@ -211,10 +248,12 @@ namespace GrossesMitainesAPI.Migrations Id = 13, Category = "Homme", Description = "En chiffon.", + Hits = 0L, ImageName = "jesus", Price = 145.45m, PromoPrice = 123.99m, Quantity = 1L, + Sales = 0L, Status = 3, Title = "Petit Jésus de plâtre" }, @@ -223,10 +262,12 @@ namespace GrossesMitainesAPI.Migrations Id = 14, Category = "Autre", Description = "À écouter dans l'habit de Bonhomme Carnaval tant que possible.", + Hits = 0L, ImageName = "vhs", Price = 3.45m, PromoPrice = 1.99m, Quantity = 164363L, + Sales = 0L, Status = 3, Title = "VHS de la Guerre des Tuques" }, @@ -235,10 +276,12 @@ namespace GrossesMitainesAPI.Migrations Id = 15, Category = "Linge", Description = "(N'est pas réellement pare-balle).", + Hits = 0L, ImageName = "chandailquetaine", Price = 1435.45m, PromoPrice = 1223.99m, Quantity = 18L, + Sales = 0L, Status = 3, Title = "Gilet pare-balle en laine" }, @@ -247,10 +290,12 @@ namespace GrossesMitainesAPI.Migrations Id = 16, Category = "Autre", Description = "Pour s'éffoirer le nez dedans.", + Hits = 0L, ImageName = "doudou", Price = 14.45m, PromoPrice = 13.99m, Quantity = 14L, + Sales = 0L, Status = 0, Title = "Doudou" }, @@ -259,10 +304,12 @@ namespace GrossesMitainesAPI.Migrations Id = 17, Category = "Vêtements d'extérieur", Description = "Pour avoir l'air thug en hiver.", + Hits = 0L, ImageName = "mitaines2", Price = 9.45m, PromoPrice = 8.99m, Quantity = 16L, + Sales = 0L, Status = 0, Title = "Mitaines pas de doigts" }); diff --git a/GrossesMitaines/GrossesMitainesAPI/Models/Product.cs b/GrossesMitaines/GrossesMitainesAPI/Models/Product.cs index 6eac294..4f72503 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Models/Product.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Models/Product.cs @@ -2,9 +2,7 @@ using System.ComponentModel.DataAnnotations; namespace GrossesMitainesAPI.Models; -// nom du produit, -// catégories, description, quantité disponible, images, prix normal et -// autres informations pertinentes + public class Product { public enum States { Available, @@ -28,5 +26,9 @@ public class Product { public decimal PromoPrice { get; set; } = 0; public uint Quantity { get; set; } = 0; public States Status { get; set; } = States.Available; + public uint Hits { get; set; } = 0; + public uint Sales { get; set; } = 0; + public DateTime? LastSale { get; set; } + public DateTime? LastHit { get; set; } public string? ImageName { get; set; } // Base pour sortir les images ({ImageName}.jpg , {ImageName}_thumbnail.jpg, etc...) } \ No newline at end of file diff --git a/GrossesMitaines/GrossesMitainesAPI/Models/ProductViewModel.cs b/GrossesMitaines/GrossesMitainesAPI/Models/ProductViewModel.cs new file mode 100644 index 0000000..b8acb2c --- /dev/null +++ b/GrossesMitaines/GrossesMitainesAPI/Models/ProductViewModel.cs @@ -0,0 +1,27 @@ +using static GrossesMitainesAPI.Models.Product; +using System.ComponentModel.DataAnnotations; + +namespace GrossesMitainesAPI.Models; +public class ProductViewModel { + public int Id { get; set; } + public string Title { get; set; } = "Erreur Aucun Objet"; + public string Category { get; set; } = "Inconnue"; + public string Description { get; set; } = "Lorem Ipsum."; + public decimal Price { get; set; } = 0; + public decimal PromoPrice { get; set; } = 0; + public uint Quantity { get; set; } = 0; + public States Status { get; set; } = States.Available; + public string? ImageName { get; set; } + + public ProductViewModel(Product prod) { + this.Id = prod.Id; + this.Title = prod.Title; + this.Category = prod.Category; + this.Description = prod.Description; + this.Price = prod.Price; + this.PromoPrice = prod.PromoPrice; + this.Quantity = prod.Quantity; + this.Status = prod.Status; + this.ImageName = prod.ImageName; + } +} diff --git a/GrossesMitaines/GrossesMitainesAPI/Services/DatabaseCacheService.cs b/GrossesMitaines/GrossesMitainesAPI/Services/DatabaseCacheService.cs index 833f13d..6603b22 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Services/DatabaseCacheService.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Services/DatabaseCacheService.cs @@ -8,6 +8,7 @@ namespace GrossesMitainesAPI.Services { private readonly ILogger _logger; private Product[] _cache = new Product[1]; + private Dictionary _hits = new(); private bool _ok = false, _needUpd = true; private PeriodicTimer _timer = new PeriodicTimer(TimeSpan.FromSeconds(10)); @@ -20,11 +21,14 @@ namespace GrossesMitainesAPI.Services { } private async void UpdateJob() { - while (await _timer.WaitForNextTickAsync()) - if (_needUpd) { + while (await _timer.WaitForNextTickAsync()) { + if (_needUpd) { _ok = UpdateCache(); _needUpd = !_ok; - } + } + if (_hits.Count > 0 && _ok) + UpdateMetrics(); + } } private bool UpdateCache() { try { @@ -42,10 +46,47 @@ namespace GrossesMitainesAPI.Services { } return true; } + + private bool UpdateMetrics() { + try { + Dictionary hits; + lock (_hits) { + hits = new(_hits); + _hits.Clear(); + } + List ids = hits.Keys.ToList(); + using (var scope = _contextFactory.CreateScope()) { + var db = scope.ServiceProvider.GetRequiredService(); + List lst = db.Products.Where(x => ids.Contains((uint)x.Id)).ToList(); + foreach (var x in hits) { + //Product prod = lst.First(x => x.Id == x.Id); + lst.First(x => x.Id == x.Id).Hits += x.Value; + // prod.Hits = prod.Hits + x.Value; + // db.Products.Update(prod); + } + db.UpdateRange(lst); + db.SaveChanges(); + } + } catch (Exception e) { + _logger.LogError(e, "Erreur de mise à jour de cache."); + return false; + } + return true; + } + public bool isOk() { return _ok; } public void askForRefresh() { _needUpd = true; } + public void addHit(uint id) { + lock (_hits) { + if (_hits.ContainsKey(id)) + _hits[id] = _hits[id] + 1; + else _hits[id] = 1; + } + } + public Product[]? GetCacheCopy() { - if (!_ok) return null; + if (!_ok) + return null; Product[] copy; try { @@ -59,9 +100,10 @@ namespace GrossesMitainesAPI.Services { } return copy; } - public IQueryable queryCache() { - if (!_ok) return null; + public IQueryable queryCache() { + if (!_ok) + return null; try { return _cache.AsQueryable(); } catch (Exception e) { diff --git a/GrossesMitaines/GrossesMitainesAPI/appsettings.json b/GrossesMitaines/GrossesMitainesAPI/appsettings.json index 7787b84..84d6132 100644 --- a/GrossesMitaines/GrossesMitainesAPI/appsettings.json +++ b/GrossesMitaines/GrossesMitainesAPI/appsettings.json @@ -7,6 +7,6 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "DefaultConnection": "Server=(localdb)\\mssqllocaldb; Database=GrossesMitainesDB3; Trusted_Connection=True; MultipleActiveResultSets=true" + "DefaultConnection": "Server=(localdb)\\mssqllocaldb; Database=GrossesMitainesDB; Trusted_Connection=True; MultipleActiveResultSets=true" } }