namespace GrossesMitainesAPI.Controllers; #region Dependencies using GrossesMitainesAPI.Models; using System.Linq; using GrossesMitainesAPI.Data; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using GrossesMitainesAPI.Services; using System.Drawing; using System.IO; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.AspNetCore.Routing; #endregion /// /// Ce contrôleur ne va pas chercher dans la cache, /// mais les changements dans celui-ci entrainera /// une demande de mise à jour dans cette dernière /// qui sera effectuée dans les 10 secondes après /// l'éxécution d'une modification de la BD. /// [EnableCors("_myAllowSpecificOrigins"), ApiController, Route("api/[controller]"), Authorize(AuthenticationSchemes = "Identity.Application", Roles = "Administrateur")] public class ProductController : ControllerBase { #region DI Fields private readonly ILogger _logger; private readonly InventoryContext _context; private readonly DatabaseCacheService _cache; private readonly IWebHostEnvironment _hostEnvironment; #endregion #region Ctor public ProductController(ILogger logger, InventoryContext context, DatabaseCacheService cache, IWebHostEnvironment hostEnvironment) { _logger = logger; _context = context; _cache = cache; _hostEnvironment = hostEnvironment; } #endregion #region API Methods [EnableCors("_myAllowSpecificOrigins"), HttpGet("Quantity"), AllowAnonymous] public ActionResult ProdCount(int id) { return _context.Products.FirstOrDefault(x => x.Id == id).Quantity; } [EnableCors("_myAllowSpecificOrigins"), HttpGet(), AllowAnonymous] public ActionResult Get(int id) { ProductModel prod; try { prod = _context.Products.Where(x => x.Id == id).First(); } catch (Exception e) { _logger.LogError(8, e.Message); return NotFound(); } _cache.addHit((uint)id); return new ProductViewModel(prod); } [EnableCors("_myAllowSpecificOrigins"), HttpPost()] public async Task> Post([FromForm] ProductModel prod) { if (prod.Price <= prod.PromoPrice) prod.PromoPrice = prod.Price - 0.01M; try { if (prod.ImageFile != null) prod.ImageName = await SaveImage(prod.ImageFile); _context.Products.Add(prod); _context.SaveChanges(); } catch (Exception e) { _logger.LogError(8, e.Message); return BadRequest(e.Message); } _cache.askForRefresh(); return prod; } [EnableCors("_myAllowSpecificOrigins"), HttpPatch()] public async Task> Patch([FromForm] ProductModel prod) { string? oldImage = ""; if (prod.Price <= prod.PromoPrice) prod.PromoPrice = prod.Price - 0.01M; try { if (prod.ImageFile is not null) { oldImage = prod.ImageName; prod.ImageName = await SaveImage(prod.ImageFile); } _context.Products.Update(prod); _context.SaveChanges(); if (oldImage is not null and not "") DeleteImages(oldImage); } catch (Exception e) { _logger.LogError(8, e.Message); return BadRequest(e.Message); } _cache.askForRefresh(); return prod; } [EnableCors("_myAllowSpecificOrigins"), HttpDelete()] public ActionResult Delete(int id) { try { var prod = _context.Products.Where(x => x.Id == id).First(); string imageName = prod.ImageName; _context.Products.Remove(prod); _context.SaveChanges(); DeleteImages(imageName); } catch (Exception e) { _logger.LogError(8, e.Message); return BadRequest(e.Message); } _cache.askForRefresh(); return id; } #endregion #region Internal Methods private async Task SaveImage(IFormFile imageFile) { string imageName = new String(Path.GetFileNameWithoutExtension(imageFile.FileName).Take(10).ToArray()).Replace(' ', '-').Replace("$",""); imageName = imageName + DateTime.Now.ToString("yymmssfff") + Path.GetExtension(imageFile.FileName); var imagePath = Path.Combine(_hostEnvironment.ContentRootPath, "Images", imageName); using (var fileStream = new FileStream(imagePath, FileMode.Create)) { await imageFile.CopyToAsync(fileStream); SaveImageThumbnail(fileStream, imageName); } return imageName; } private void SaveImageThumbnail(FileStream stream, string imageName) { try { const float maxSize = 300f; Image image = Image.FromStream(stream); //Choisi le bon ratio de division pour ne pas dépasser le 300px ni dans height ni dans width float ratio = image.Width / (image.Height / maxSize) <= maxSize ? image.Height / maxSize : image.Width / maxSize; Bitmap resize = new Bitmap(image, new Size((int)(image.Width / ratio), (int)(image.Height / ratio))); string path = Path.Combine(_hostEnvironment.ContentRootPath, "Images", Path.GetFileNameWithoutExtension(imageName) + "_thumbnail" + Path.GetExtension(imageName)); resize.Save(path); } catch (Exception ex) { _logger.LogError(8, ex.Message); } } private void DeleteImages(string imageName) { if (imageName == "default.jpg" || imageName == "default_thumbnail.jpg" || imageName.Contains("$")) return; var files = System.IO.Directory.GetFiles(_hostEnvironment.ContentRootPath + "/Images") .Where(x => x.Contains(Path.GetFileNameWithoutExtension(imageName))).ToArray(); foreach (var file in files) System.IO.File.Delete(file); } #endregion }