Gossage dans API

This commit is contained in:
MarcEricMartel 2022-10-27 09:37:13 -07:00
parent 04c7d68a44
commit 83331a4a08
10 changed files with 213 additions and 39 deletions

View File

@ -5,6 +5,7 @@ using GrossesMitainesAPI.Data;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using GrossesMitainesAPI.Services; using GrossesMitainesAPI.Services;
using Microsoft.AspNetCore.Authorization;
namespace GrossesMitainesAPI.Controllers; namespace GrossesMitainesAPI.Controllers;
@ -22,7 +23,7 @@ public class InventoryController : Controller {
_cache = cache; _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<Product> Get(int? lastId, string? order, string? filterPrice, string? filterState, bool? all) { public IEnumerable<Product> Get(int? lastId, string? order, string? filterPrice, string? filterState, bool? all) {
bool islock = false; bool islock = false;
IQueryable<Product> ret; IQueryable<Product> ret;
@ -127,7 +128,7 @@ public class InventoryController : Controller {
} }
} }
// Inventory/Delete => Décrémenter un produit. Va aller chercher directement dans la BD. // 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<int> Delete(int? id) { public ActionResult<int> Delete(int? id) {
int rid = 0; int rid = 0;
if (!id.HasValue) { if (!id.HasValue) {
@ -139,6 +140,8 @@ public class InventoryController : Controller {
rid = prod.Id; rid = prod.Id;
if (prod.Quantity > 0) { if (prod.Quantity > 0) {
prod.Quantity = prod.Quantity - 1; prod.Quantity = prod.Quantity - 1;
prod.Sales = prod.Sales + 1;
prod.LastSale = DateTime.Now;
if (prod.Quantity == 0) if (prod.Quantity == 0)
prod.Status = prod.Status == Product.States.Clearance? prod.Status = prod.Status == Product.States.Clearance?
Product.States.Discontinued: Product.States.Discontinued:

View File

@ -29,7 +29,7 @@ public class ProductController : ControllerBase {
} }
[EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Product"), AllowAnonymous] [EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Product"), AllowAnonymous]
public ActionResult<Product> Get(int id) { public ActionResult<ProductViewModel> Get(int id) {
Product prod; Product prod;
try { try {
prod = _context.Products.Where(x => x.Id == id).First(); prod = _context.Products.Where(x => x.Id == id).First();
@ -38,7 +38,8 @@ public class ProductController : ControllerBase {
_logger.LogError(8, e.Message); _logger.LogError(8, e.Message);
return NotFound(); return NotFound();
} }
return prod; _cache.addHit((uint)id);
return new ProductViewModel(prod);
} }
[EnableCors("_myAllowSpecificOrigins"), HttpPost(Name = "Product")] [EnableCors("_myAllowSpecificOrigins"), HttpPost(Name = "Product")]

View File

@ -26,14 +26,14 @@ public class SearchController : Controller {
_searchCache = _cache.GetCacheCopy(); _searchCache = _cache.GetCacheCopy();
} }
[EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Search")] [EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Search"), AllowAnonymous]
public IEnumerable<Product> Get(string query, bool? preview, bool? deep) { public IEnumerable<Product> Get(string query, bool? preview, bool? deep) {
if (_searchCache is not null) if (_searchCache is not null)
return SearchCached(query, preview, deep); return SearchCached(query, preview, deep);
else return Search(query, preview, deep); else return SearchDirect(query, preview, deep);
} }
private List<Product> Search(string query, bool? preview, bool? deep) { private List<Product> SearchDirect(string query, bool? preview, bool? deep) {
List<Product> products = new(); List<Product> products = new();
query = query.Trim(); query = query.Trim();
try { // Pour faire une liste priorisée. try { // Pour faire une liste priorisée.
@ -80,7 +80,7 @@ public class SearchController : Controller {
query = query.Trim(); query = query.Trim();
if (_searchCache is null) { if (_searchCache is null) {
_logger.LogError(8, "Erreur de cache."); _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. try { // Pour faire une liste priorisée.
if (preview.HasValue && preview == true) if (preview.HasValue && preview == true)
@ -117,7 +117,7 @@ public class SearchController : Controller {
} }
} catch (Exception e) { } catch (Exception e) {
_logger.LogError(8, e.Message); _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; return products;
} }

View File

@ -1,4 +1,5 @@
// <auto-generated /> // <auto-generated />
using System;
using GrossesMitainesAPI.Data; using GrossesMitainesAPI.Data;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
@ -11,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace GrossesMitainesAPI.Migrations namespace GrossesMitainesAPI.Migrations
{ {
[DbContext(typeof(InventoryContext))] [DbContext(typeof(InventoryContext))]
[Migration("20221025170101_Initial-Db")] [Migration("20221027160052_Initial-Db")]
partial class InitialDb partial class InitialDb
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -39,9 +40,18 @@ namespace GrossesMitainesAPI.Migrations
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<long>("Hits")
.HasColumnType("bigint");
b.Property<string>("ImageName") b.Property<string>("ImageName")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<DateTime?>("LastHit")
.HasColumnType("datetime2");
b.Property<DateTime?>("LastSale")
.HasColumnType("datetime2");
b.Property<decimal>("Price") b.Property<decimal>("Price")
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
@ -51,6 +61,9 @@ namespace GrossesMitainesAPI.Migrations
b.Property<long>("Quantity") b.Property<long>("Quantity")
.HasColumnType("bigint"); .HasColumnType("bigint");
b.Property<long>("Sales")
.HasColumnType("bigint");
b.Property<int>("Status") b.Property<int>("Status")
.HasColumnType("int"); .HasColumnType("int");
@ -69,10 +82,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 1, Id = 1,
Category = "Linge", Category = "Linge",
Description = "Pour faire votre propre bonhomme de 1837, comme dans le bon vieux temps.", Description = "Pour faire votre propre bonhomme de 1837, comme dans le bon vieux temps.",
Hits = 0L,
ImageName = "ceintureflechee", ImageName = "ceintureflechee",
Price = 85.86m, Price = 85.86m,
PromoPrice = 29.99m, PromoPrice = 29.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Ceinture flèchée" Title = "Ceinture flèchée"
}, },
@ -81,10 +96,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 2, Id = 2,
Category = "Linge", Category = "Linge",
Description = "Parce que ça sent la coupe!", Description = "Parce que ça sent la coupe!",
Hits = 0L,
ImageName = "pantouflesCH", ImageName = "pantouflesCH",
Price = 15.64m, Price = 15.64m,
PromoPrice = 9.99m, PromoPrice = 9.99m,
Quantity = 54L, Quantity = 54L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Pantoufles du Canadien en Phentex" Title = "Pantoufles du Canadien en Phentex"
}, },
@ -93,10 +110,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 3, Id = 3,
Category = "Homme", Category = "Homme",
Description = "On ne lui ferait pas mal, en tout cas!!", Description = "On ne lui ferait pas mal, en tout cas!!",
Hits = 0L,
ImageName = "jeanlucmongrain", ImageName = "jeanlucmongrain",
Price = 1453.12m, Price = 1453.12m,
PromoPrice = 999.99m, PromoPrice = 999.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 3, Status = 3,
Title = "Jean-Luc Mongrain" Title = "Jean-Luc Mongrain"
}, },
@ -105,10 +124,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 4, Id = 4,
Category = "Linge", Category = "Linge",
Description = "Tellement simple et comfortable.", Description = "Tellement simple et comfortable.",
Hits = 0L,
ImageName = "tshirt", ImageName = "tshirt",
Price = 12.12m, Price = 12.12m,
PromoPrice = 9.99m, PromoPrice = 9.99m,
Quantity = 143L, Quantity = 143L,
Sales = 0L,
Status = 0, Status = 0,
Title = "T-Shirt" Title = "T-Shirt"
}, },
@ -117,10 +138,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 5, Id = 5,
Category = "Vêtement d'extérieur", Category = "Vêtement d'extérieur",
Description = "Deux pour un!", Description = "Deux pour un!",
Hits = 0L,
ImageName = "mitaines", ImageName = "mitaines",
Price = 8.18m, Price = 8.18m,
PromoPrice = 6.99m, PromoPrice = 6.99m,
Quantity = 1423L, Quantity = 1423L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Mitaines" Title = "Mitaines"
}, },
@ -129,10 +152,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 6, Id = 6,
Category = "Vêtement d'extérieur", Category = "Vêtement d'extérieur",
Description = "Deux pour un!", Description = "Deux pour un!",
Hits = 0L,
ImageName = "foulard", ImageName = "foulard",
Price = 10.56m, Price = 10.56m,
PromoPrice = 8.99m, PromoPrice = 8.99m,
Quantity = 14L, Quantity = 14L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Foulard" Title = "Foulard"
}, },
@ -141,10 +166,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 7, Id = 7,
Category = "Sous-Vêtement", Category = "Sous-Vêtement",
Description = "Pour garder le p'tit bout au chaud.", Description = "Pour garder le p'tit bout au chaud.",
Hits = 0L,
ImageName = "kokin", ImageName = "kokin",
Price = 15.45m, Price = 15.45m,
PromoPrice = 12.99m, PromoPrice = 12.99m,
Quantity = 144L, Quantity = 144L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Jock-Strap en phentex" Title = "Jock-Strap en phentex"
}, },
@ -153,10 +180,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 8, Id = 8,
Category = "Sous-Vêtement", Category = "Sous-Vêtement",
Description = "Pour garder l'absence de p'tit bout au chaud.", Description = "Pour garder l'absence de p'tit bout au chaud.",
Hits = 0L,
ImageName = "kokin", ImageName = "kokin",
Price = 15.45m, Price = 15.45m,
PromoPrice = 12.99m, PromoPrice = 12.99m,
Quantity = 224L, Quantity = 224L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Jock-Strap féminin en phentex" Title = "Jock-Strap féminin en phentex"
}, },
@ -165,10 +194,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 9, Id = 9,
Category = "Alien", Category = "Alien",
Description = "En chiffon.", Description = "En chiffon.",
Hits = 0L,
ImageName = "bibi", ImageName = "bibi",
Price = 1045.45m, Price = 1045.45m,
PromoPrice = 1023.99m, PromoPrice = 1023.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 3, Status = 3,
Title = "Bibi" Title = "Bibi"
}, },
@ -177,10 +208,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 10, Id = 10,
Category = "Vêtement d'extérieur", Category = "Vêtement d'extérieur",
Description = "En chiffon.", Description = "En chiffon.",
Hits = 0L,
ImageName = "tuque", ImageName = "tuque",
Price = 15.45m, Price = 15.45m,
PromoPrice = 12.99m, PromoPrice = 12.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Tuque en laine" Title = "Tuque en laine"
}, },
@ -189,10 +222,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 11, Id = 11,
Category = "Vêtement d'extérieur", Category = "Vêtement d'extérieur",
Description = "Pour se faire taper dessus avec une poêle à frire tout en restant au chaud.", Description = "Pour se faire taper dessus avec une poêle à frire tout en restant au chaud.",
Hits = 0L,
ImageName = "bonhomme", ImageName = "bonhomme",
Price = 145.45m, Price = 145.45m,
PromoPrice = 123.99m, PromoPrice = 123.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Habit de Bonhomme Carnaval" Title = "Habit de Bonhomme Carnaval"
}, },
@ -201,10 +236,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 12, Id = 12,
Category = "Autre", Category = "Autre",
Description = "Pour se pêter la fiole avec style.", Description = "Pour se pêter la fiole avec style.",
Hits = 0L,
ImageName = "gauze", ImageName = "gauze",
Price = 145.45m, Price = 145.45m,
PromoPrice = 123.99m, PromoPrice = 123.99m,
Quantity = 0L, Quantity = 0L,
Sales = 0L,
Status = 1, Status = 1,
Title = "Gauze en phentex" Title = "Gauze en phentex"
}, },
@ -213,10 +250,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 13, Id = 13,
Category = "Homme", Category = "Homme",
Description = "En chiffon.", Description = "En chiffon.",
Hits = 0L,
ImageName = "jesus", ImageName = "jesus",
Price = 145.45m, Price = 145.45m,
PromoPrice = 123.99m, PromoPrice = 123.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 3, Status = 3,
Title = "Petit Jésus de plâtre" Title = "Petit Jésus de plâtre"
}, },
@ -225,10 +264,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 14, Id = 14,
Category = "Autre", Category = "Autre",
Description = "À écouter dans l'habit de Bonhomme Carnaval tant que possible.", Description = "À écouter dans l'habit de Bonhomme Carnaval tant que possible.",
Hits = 0L,
ImageName = "vhs", ImageName = "vhs",
Price = 3.45m, Price = 3.45m,
PromoPrice = 1.99m, PromoPrice = 1.99m,
Quantity = 164363L, Quantity = 164363L,
Sales = 0L,
Status = 3, Status = 3,
Title = "VHS de la Guerre des Tuques" Title = "VHS de la Guerre des Tuques"
}, },
@ -237,10 +278,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 15, Id = 15,
Category = "Linge", Category = "Linge",
Description = "(N'est pas réellement pare-balle).", Description = "(N'est pas réellement pare-balle).",
Hits = 0L,
ImageName = "chandailquetaine", ImageName = "chandailquetaine",
Price = 1435.45m, Price = 1435.45m,
PromoPrice = 1223.99m, PromoPrice = 1223.99m,
Quantity = 18L, Quantity = 18L,
Sales = 0L,
Status = 3, Status = 3,
Title = "Gilet pare-balle en laine" Title = "Gilet pare-balle en laine"
}, },
@ -249,10 +292,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 16, Id = 16,
Category = "Autre", Category = "Autre",
Description = "Pour s'éffoirer le nez dedans.", Description = "Pour s'éffoirer le nez dedans.",
Hits = 0L,
ImageName = "doudou", ImageName = "doudou",
Price = 14.45m, Price = 14.45m,
PromoPrice = 13.99m, PromoPrice = 13.99m,
Quantity = 14L, Quantity = 14L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Doudou" Title = "Doudou"
}, },
@ -261,10 +306,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 17, Id = 17,
Category = "Vêtements d'extérieur", Category = "Vêtements d'extérieur",
Description = "Pour avoir l'air thug en hiver.", Description = "Pour avoir l'air thug en hiver.",
Hits = 0L,
ImageName = "mitaines2", ImageName = "mitaines2",
Price = 9.45m, Price = 9.45m,
PromoPrice = 8.99m, PromoPrice = 8.99m,
Quantity = 16L, Quantity = 16L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Mitaines pas de doigts" Title = "Mitaines pas de doigts"
}); });

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore.Migrations; using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable #nullable disable
@ -21,6 +22,10 @@ namespace GrossesMitainesAPI.Migrations
PromoPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false), PromoPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
Quantity = table.Column<long>(type: "bigint", nullable: false), Quantity = table.Column<long>(type: "bigint", nullable: false),
Status = table.Column<int>(type: "int", nullable: false), Status = table.Column<int>(type: "int", nullable: false),
Hits = table.Column<long>(type: "bigint", nullable: false),
Sales = table.Column<long>(type: "bigint", nullable: false),
LastSale = table.Column<DateTime>(type: "datetime2", nullable: true),
LastHit = table.Column<DateTime>(type: "datetime2", nullable: true),
ImageName = table.Column<string>(type: "nvarchar(max)", nullable: true) ImageName = table.Column<string>(type: "nvarchar(max)", nullable: true)
}, },
constraints: table => constraints: table =>
@ -30,26 +35,26 @@ namespace GrossesMitainesAPI.Migrations
migrationBuilder.InsertData( migrationBuilder.InsertData(
table: "Products", 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[,] 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" }, { 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!", "pantouflesCH", 15.64m, 9.99m, 54L, 0, "Pantoufles du Canadien en Phentex" }, { 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!!", "jeanlucmongrain", 1453.12m, 999.99m, 1L, 3, "Jean-Luc Mongrain" }, { 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.", "tshirt", 12.12m, 9.99m, 143L, 0, "T-Shirt" }, { 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!", "mitaines", 8.18m, 6.99m, 1423L, 0, "Mitaines" }, { 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!", "foulard", 10.56m, 8.99m, 14L, 4, "Foulard" }, { 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.", "kokin", 15.45m, 12.99m, 144L, 4, "Jock-Strap en phentex" }, { 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.", "kokin", 15.45m, 12.99m, 224L, 4, "Jock-Strap féminin 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.", "bibi", 1045.45m, 1023.99m, 1L, 3, "Bibi" }, { 9, "Alien", "En chiffon.", 0L, "bibi", null, null, 1045.45m, 1023.99m, 1L, 0L, 3, "Bibi" },
{ 10, "Vêtement d'extérieur", "En chiffon.", "tuque", 15.45m, 12.99m, 1L, 0, "Tuque en laine" }, { 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.", "bonhomme", 145.45m, 123.99m, 1L, 4, "Habit de Bonhomme Carnaval" }, { 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.", "gauze", 145.45m, 123.99m, 0L, 1, "Gauze en phentex" }, { 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.", "jesus", 145.45m, 123.99m, 1L, 3, "Petit Jésus de plâtre" }, { 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.", "vhs", 3.45m, 1.99m, 164363L, 3, "VHS de la Guerre des Tuques" }, { 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).", "chandailquetaine", 1435.45m, 1223.99m, 18L, 3, "Gilet pare-balle en laine" }, { 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.", "doudou", 14.45m, 13.99m, 14L, 0, "Doudou" }, { 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.", "mitaines2", 9.45m, 8.99m, 16L, 0, "Mitaines pas de doigts" } { 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" }
}); });
} }

View File

@ -1,4 +1,5 @@
// <auto-generated /> // <auto-generated />
using System;
using GrossesMitainesAPI.Data; using GrossesMitainesAPI.Data;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
@ -37,9 +38,18 @@ namespace GrossesMitainesAPI.Migrations
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<long>("Hits")
.HasColumnType("bigint");
b.Property<string>("ImageName") b.Property<string>("ImageName")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<DateTime?>("LastHit")
.HasColumnType("datetime2");
b.Property<DateTime?>("LastSale")
.HasColumnType("datetime2");
b.Property<decimal>("Price") b.Property<decimal>("Price")
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
@ -49,6 +59,9 @@ namespace GrossesMitainesAPI.Migrations
b.Property<long>("Quantity") b.Property<long>("Quantity")
.HasColumnType("bigint"); .HasColumnType("bigint");
b.Property<long>("Sales")
.HasColumnType("bigint");
b.Property<int>("Status") b.Property<int>("Status")
.HasColumnType("int"); .HasColumnType("int");
@ -67,10 +80,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 1, Id = 1,
Category = "Linge", Category = "Linge",
Description = "Pour faire votre propre bonhomme de 1837, comme dans le bon vieux temps.", Description = "Pour faire votre propre bonhomme de 1837, comme dans le bon vieux temps.",
Hits = 0L,
ImageName = "ceintureflechee", ImageName = "ceintureflechee",
Price = 85.86m, Price = 85.86m,
PromoPrice = 29.99m, PromoPrice = 29.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Ceinture flèchée" Title = "Ceinture flèchée"
}, },
@ -79,10 +94,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 2, Id = 2,
Category = "Linge", Category = "Linge",
Description = "Parce que ça sent la coupe!", Description = "Parce que ça sent la coupe!",
Hits = 0L,
ImageName = "pantouflesCH", ImageName = "pantouflesCH",
Price = 15.64m, Price = 15.64m,
PromoPrice = 9.99m, PromoPrice = 9.99m,
Quantity = 54L, Quantity = 54L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Pantoufles du Canadien en Phentex" Title = "Pantoufles du Canadien en Phentex"
}, },
@ -91,10 +108,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 3, Id = 3,
Category = "Homme", Category = "Homme",
Description = "On ne lui ferait pas mal, en tout cas!!", Description = "On ne lui ferait pas mal, en tout cas!!",
Hits = 0L,
ImageName = "jeanlucmongrain", ImageName = "jeanlucmongrain",
Price = 1453.12m, Price = 1453.12m,
PromoPrice = 999.99m, PromoPrice = 999.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 3, Status = 3,
Title = "Jean-Luc Mongrain" Title = "Jean-Luc Mongrain"
}, },
@ -103,10 +122,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 4, Id = 4,
Category = "Linge", Category = "Linge",
Description = "Tellement simple et comfortable.", Description = "Tellement simple et comfortable.",
Hits = 0L,
ImageName = "tshirt", ImageName = "tshirt",
Price = 12.12m, Price = 12.12m,
PromoPrice = 9.99m, PromoPrice = 9.99m,
Quantity = 143L, Quantity = 143L,
Sales = 0L,
Status = 0, Status = 0,
Title = "T-Shirt" Title = "T-Shirt"
}, },
@ -115,10 +136,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 5, Id = 5,
Category = "Vêtement d'extérieur", Category = "Vêtement d'extérieur",
Description = "Deux pour un!", Description = "Deux pour un!",
Hits = 0L,
ImageName = "mitaines", ImageName = "mitaines",
Price = 8.18m, Price = 8.18m,
PromoPrice = 6.99m, PromoPrice = 6.99m,
Quantity = 1423L, Quantity = 1423L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Mitaines" Title = "Mitaines"
}, },
@ -127,10 +150,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 6, Id = 6,
Category = "Vêtement d'extérieur", Category = "Vêtement d'extérieur",
Description = "Deux pour un!", Description = "Deux pour un!",
Hits = 0L,
ImageName = "foulard", ImageName = "foulard",
Price = 10.56m, Price = 10.56m,
PromoPrice = 8.99m, PromoPrice = 8.99m,
Quantity = 14L, Quantity = 14L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Foulard" Title = "Foulard"
}, },
@ -139,10 +164,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 7, Id = 7,
Category = "Sous-Vêtement", Category = "Sous-Vêtement",
Description = "Pour garder le p'tit bout au chaud.", Description = "Pour garder le p'tit bout au chaud.",
Hits = 0L,
ImageName = "kokin", ImageName = "kokin",
Price = 15.45m, Price = 15.45m,
PromoPrice = 12.99m, PromoPrice = 12.99m,
Quantity = 144L, Quantity = 144L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Jock-Strap en phentex" Title = "Jock-Strap en phentex"
}, },
@ -151,10 +178,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 8, Id = 8,
Category = "Sous-Vêtement", Category = "Sous-Vêtement",
Description = "Pour garder l'absence de p'tit bout au chaud.", Description = "Pour garder l'absence de p'tit bout au chaud.",
Hits = 0L,
ImageName = "kokin", ImageName = "kokin",
Price = 15.45m, Price = 15.45m,
PromoPrice = 12.99m, PromoPrice = 12.99m,
Quantity = 224L, Quantity = 224L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Jock-Strap féminin en phentex" Title = "Jock-Strap féminin en phentex"
}, },
@ -163,10 +192,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 9, Id = 9,
Category = "Alien", Category = "Alien",
Description = "En chiffon.", Description = "En chiffon.",
Hits = 0L,
ImageName = "bibi", ImageName = "bibi",
Price = 1045.45m, Price = 1045.45m,
PromoPrice = 1023.99m, PromoPrice = 1023.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 3, Status = 3,
Title = "Bibi" Title = "Bibi"
}, },
@ -175,10 +206,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 10, Id = 10,
Category = "Vêtement d'extérieur", Category = "Vêtement d'extérieur",
Description = "En chiffon.", Description = "En chiffon.",
Hits = 0L,
ImageName = "tuque", ImageName = "tuque",
Price = 15.45m, Price = 15.45m,
PromoPrice = 12.99m, PromoPrice = 12.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Tuque en laine" Title = "Tuque en laine"
}, },
@ -187,10 +220,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 11, Id = 11,
Category = "Vêtement d'extérieur", Category = "Vêtement d'extérieur",
Description = "Pour se faire taper dessus avec une poêle à frire tout en restant au chaud.", Description = "Pour se faire taper dessus avec une poêle à frire tout en restant au chaud.",
Hits = 0L,
ImageName = "bonhomme", ImageName = "bonhomme",
Price = 145.45m, Price = 145.45m,
PromoPrice = 123.99m, PromoPrice = 123.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 4, Status = 4,
Title = "Habit de Bonhomme Carnaval" Title = "Habit de Bonhomme Carnaval"
}, },
@ -199,10 +234,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 12, Id = 12,
Category = "Autre", Category = "Autre",
Description = "Pour se pêter la fiole avec style.", Description = "Pour se pêter la fiole avec style.",
Hits = 0L,
ImageName = "gauze", ImageName = "gauze",
Price = 145.45m, Price = 145.45m,
PromoPrice = 123.99m, PromoPrice = 123.99m,
Quantity = 0L, Quantity = 0L,
Sales = 0L,
Status = 1, Status = 1,
Title = "Gauze en phentex" Title = "Gauze en phentex"
}, },
@ -211,10 +248,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 13, Id = 13,
Category = "Homme", Category = "Homme",
Description = "En chiffon.", Description = "En chiffon.",
Hits = 0L,
ImageName = "jesus", ImageName = "jesus",
Price = 145.45m, Price = 145.45m,
PromoPrice = 123.99m, PromoPrice = 123.99m,
Quantity = 1L, Quantity = 1L,
Sales = 0L,
Status = 3, Status = 3,
Title = "Petit Jésus de plâtre" Title = "Petit Jésus de plâtre"
}, },
@ -223,10 +262,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 14, Id = 14,
Category = "Autre", Category = "Autre",
Description = "À écouter dans l'habit de Bonhomme Carnaval tant que possible.", Description = "À écouter dans l'habit de Bonhomme Carnaval tant que possible.",
Hits = 0L,
ImageName = "vhs", ImageName = "vhs",
Price = 3.45m, Price = 3.45m,
PromoPrice = 1.99m, PromoPrice = 1.99m,
Quantity = 164363L, Quantity = 164363L,
Sales = 0L,
Status = 3, Status = 3,
Title = "VHS de la Guerre des Tuques" Title = "VHS de la Guerre des Tuques"
}, },
@ -235,10 +276,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 15, Id = 15,
Category = "Linge", Category = "Linge",
Description = "(N'est pas réellement pare-balle).", Description = "(N'est pas réellement pare-balle).",
Hits = 0L,
ImageName = "chandailquetaine", ImageName = "chandailquetaine",
Price = 1435.45m, Price = 1435.45m,
PromoPrice = 1223.99m, PromoPrice = 1223.99m,
Quantity = 18L, Quantity = 18L,
Sales = 0L,
Status = 3, Status = 3,
Title = "Gilet pare-balle en laine" Title = "Gilet pare-balle en laine"
}, },
@ -247,10 +290,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 16, Id = 16,
Category = "Autre", Category = "Autre",
Description = "Pour s'éffoirer le nez dedans.", Description = "Pour s'éffoirer le nez dedans.",
Hits = 0L,
ImageName = "doudou", ImageName = "doudou",
Price = 14.45m, Price = 14.45m,
PromoPrice = 13.99m, PromoPrice = 13.99m,
Quantity = 14L, Quantity = 14L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Doudou" Title = "Doudou"
}, },
@ -259,10 +304,12 @@ namespace GrossesMitainesAPI.Migrations
Id = 17, Id = 17,
Category = "Vêtements d'extérieur", Category = "Vêtements d'extérieur",
Description = "Pour avoir l'air thug en hiver.", Description = "Pour avoir l'air thug en hiver.",
Hits = 0L,
ImageName = "mitaines2", ImageName = "mitaines2",
Price = 9.45m, Price = 9.45m,
PromoPrice = 8.99m, PromoPrice = 8.99m,
Quantity = 16L, Quantity = 16L,
Sales = 0L,
Status = 0, Status = 0,
Title = "Mitaines pas de doigts" Title = "Mitaines pas de doigts"
}); });

View File

@ -2,9 +2,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace GrossesMitainesAPI.Models; namespace GrossesMitainesAPI.Models;
// nom du produit,
// catégories, description, quantité disponible, images, prix normal et
// autres informations pertinentes
public class Product { public class Product {
public enum States { public enum States {
Available, Available,
@ -28,5 +26,9 @@ public class Product {
public decimal PromoPrice { get; set; } = 0; public decimal PromoPrice { get; set; } = 0;
public uint Quantity { get; set; } = 0; public uint Quantity { get; set; } = 0;
public States Status { get; set; } = States.Available; 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...) public string? ImageName { get; set; } // Base pour sortir les images ({ImageName}.jpg , {ImageName}_thumbnail.jpg, etc...)
} }

View File

@ -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;
}
}

View File

@ -8,6 +8,7 @@ namespace GrossesMitainesAPI.Services {
private readonly ILogger<DatabaseCacheService> _logger; private readonly ILogger<DatabaseCacheService> _logger;
private Product[] _cache = new Product[1]; private Product[] _cache = new Product[1];
private Dictionary<uint, uint> _hits = new();
private bool _ok = false, _needUpd = true; private bool _ok = false, _needUpd = true;
private PeriodicTimer _timer = new PeriodicTimer(TimeSpan.FromSeconds(10)); private PeriodicTimer _timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
@ -20,11 +21,14 @@ namespace GrossesMitainesAPI.Services {
} }
private async void UpdateJob() { private async void UpdateJob() {
while (await _timer.WaitForNextTickAsync()) while (await _timer.WaitForNextTickAsync()) {
if (_needUpd) { if (_needUpd) {
_ok = UpdateCache(); _ok = UpdateCache();
_needUpd = !_ok; _needUpd = !_ok;
} }
if (_hits.Count > 0 && _ok)
UpdateMetrics();
}
} }
private bool UpdateCache() { private bool UpdateCache() {
try { try {
@ -42,10 +46,47 @@ namespace GrossesMitainesAPI.Services {
} }
return true; return true;
} }
private bool UpdateMetrics() {
try {
Dictionary<uint, uint> hits;
lock (_hits) {
hits = new(_hits);
_hits.Clear();
}
List<uint> ids = hits.Keys.ToList();
using (var scope = _contextFactory.CreateScope()) {
var db = scope.ServiceProvider.GetRequiredService<InventoryContext>();
List<Product> 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 bool isOk() { return _ok; }
public void askForRefresh() { _needUpd = true; } 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() { public Product[]? GetCacheCopy() {
if (!_ok) return null; if (!_ok)
return null;
Product[] copy; Product[] copy;
try { try {
@ -59,9 +100,10 @@ namespace GrossesMitainesAPI.Services {
} }
return copy; return copy;
} }
public IQueryable<Product> queryCache() {
if (!_ok) return null;
public IQueryable<Product> queryCache() {
if (!_ok)
return null;
try { try {
return _cache.AsQueryable(); return _cache.AsQueryable();
} catch (Exception e) { } catch (Exception e) {

View File

@ -7,6 +7,6 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb; Database=GrossesMitainesDB3; Trusted_Connection=True; MultipleActiveResultSets=true" "DefaultConnection": "Server=(localdb)\\mssqllocaldb; Database=GrossesMitainesDB; Trusted_Connection=True; MultipleActiveResultSets=true"
} }
} }