Merge remote-tracking branch 'origin/j2/refactor/controler-style-titre' into j2/ajout_repo

This commit is contained in:
Loic Masi
2026-03-26 13:57:56 +01:00
45 changed files with 1627 additions and 6747 deletions

View File

@@ -1,17 +1,46 @@
// using Webzine.Entity;
namespace Webzine.Repository.Contracts
{
using Webzine.Entity;
/// <summary>
/// Défini une interface <see cref="IArtisteRepository"/> pour gérer les opérations de base de données liées aux artistes.
/// </summary>
public interface IArtisteRepository
{
// void Add(Artiste artiste);
/// <summary>
/// Ajoute un nouvel artiste.
/// </summary>
/// <param name="artiste">L'artiste à ajouter à la collection. Ne peut pas être null.</param>
void Add(Artiste artiste);
// void Delete(Artiste artiste);
/// <summary>
/// Supprime un artiste.
/// </summary>
/// <param name="artiste">L'artiste à supprimer.</param>
void Delete(Artiste artiste);
// Artiste Find(int id);
/// <summary>
/// Récupère un artiste par son identifiant unique. Si aucun artiste n'est trouvé, retourne null.
/// </summary>
/// <param name="id">L'identifiant de l'artiste.</param>
/// <returns></returns>
Artiste Find(int id);
/// <summary>
/// Récupère un artiste par son nom. Si aucun artiste n'est trouvé, retourne null.
/// </summary>
/// <param name="name">Le nom de l'artiste.</param>
/// <returns>L'artiste recherché ou null.</returns>
Artiste FindByName(string name);
// IEnumerable<Artiste> FindAll();
/// <summary>
/// Récupère tous les artistes disponibles dans la collection. Si aucun artiste n'est trouvé, retourne une collection vide.
/// </summary>
/// <returns>Retourne une collection d'artistes.</returns>
IEnumerable<Artiste> FindAll();
// void Update(Artiste artiste);
/// <summary>
/// Met à jour les informations d'un artiste existant dans la collection.
/// </summary>
/// <param name="artiste">L'artiste à mettre à jour.</param>
void Update(Artiste artiste);
}
}

View File

@@ -1,15 +1,15 @@
// using Webzine.Entity;
using Webzine.Entity;
namespace Webzine.Repository.Contracts
{
public interface ICommentaireRepository
{
// void Add(Commentaire commentaire);
void Add(Commentaire commentaire);
// void Delete(Commentaire commentaire);
void Delete(Commentaire commentaire);
// Commentaire Find(int id);
Commentaire Find(int id);
// IEnumerable<Commentaire> FindAll();
IEnumerable<Commentaire> FindAll();
}
}

View File

@@ -1,17 +1,41 @@
// using Webzine.Entity;
using Webzine.Entity;
namespace Webzine.Repository.Contracts
{
/// <summary>
/// Interface définissant les opérations de base pour le repository de styles, permettant d'ajouter, supprimer, trouver et mettre à jour des styles dans la source de données.
/// </summary>
public interface IStyleRepository
{
// void Add(Style style);
/// <summary>
/// Ajoute un style à la liste des styles.
/// </summary>
/// <param name="style">L'objet style à ajouter.</param>
void Add(Style style);
// void Delete(Style style);
/// <summary>
/// Supprime un style de la liste des styles.
/// </summary>
/// <param name="style">L'objet style à supprimer.</param>
void Delete(Style style);
// Style Find(int id);
/// <summary>
/// Trouve un style dans la liste des styles en fonction de son identifiant.
/// </summary>
/// <param name="id">L'identifiant du style à trouver.</param>
/// <returns>Le style correspondant à l'identifiant fourni, ou null si aucun style n'est trouvé.</returns>
Style Find(int id);
// IEnumerable<Style> FindAll();
/// <summary>
/// Trouve tous les styles dans la liste des styles.
/// </summary>
/// <returns>Une collection de tous les styles présents dans la liste.</returns>
IEnumerable<Style> FindAll();
// void Update(Style style);
/// <summary>
/// Met à jour un style dans la liste des styles en fonction de son identifiant.
/// </summary>
/// <param name="style">L'objet style à mettre à jour.</param
void Update(Style style);
}
}

View File

@@ -0,0 +1,81 @@
using Webzine.Entity;
namespace Webzine.Repository.Contracts
{
/// <summary>
/// Interface qui définit les opérations de base pour la gestion des titres dans une source de données.
/// </summary>
public interface ITitreRepository
{
/// <summary>
/// Ajoute un titre à la liste des titres.
/// </summary>
/// <param name="titre">L'objet titre à ajouter.</param>
void Add(Titre titre);
/// <summary>
/// Remonte le nombre de titres.
/// </summary>
/// <returns>Le nombre total de titres présents dans la liste après l'incrémentation du nombre de lectures.</returns>
int Count();
/// <summary>
/// Supprime un titre de la liste des titres.
/// </summary>
/// <param name="titre">L'objet titre à supprimer.</param>
void Delete(Titre titre);
/// <summary>
/// Trouve un titre dans la liste des titres en fonction de son identifiant.
/// </summary>
/// <param name="idTitre">L'identifiant du titre à trouver.</param>
/// <returns>Le titre correspondant à l'identifiant fourni, ou null si aucun titre n'est trouvé.</returns>
Titre Find(int idTitre);
/// <summary>
/// Recherche les titres dans la liste des titres en fonction de l'offset et de la limite spécifiés, permettant ainsi une pagination des résultats.
/// </summary>
/// <param name="offset">Le nombre de titres à ignorer avant de commencer à retourner les résultats.</param>
/// <param name="limit">Le nombre maximum de titres à retourner.</param>
/// <returns>Une collection de titres correspondant au critère de pagination, triée par libellé.</returns>
IEnumerable<Titre> FindTitres(int offset, int limit);
/// <summary>
/// Trouve tous les titres dans la liste des titres.
/// </summary>
/// <returns>Une collection de tous les titres présents dans la liste.</returns>
IEnumerable<Titre> FindAll();
/// <summary>
/// Incrémente le nombre de lectures d'un titre donné. Si le titre est null, un message d'avertissement est enregistré dans les logs et aucune action n'est effectuée.
/// </summary>
/// <param name="titre">L'objet titre dont le nombre de lectures doit être incrémenté.</param>
void IncrementNbLectures(Titre titre);
/// <summary>
/// Incrémente le nombre de likes d'un titre donné. Si le titre est null, un message d'avertissement est enregistré dans les logs et aucune action n'est effectuée.
/// </summary>
/// <param name="titre">L'objet titre dont le nombre de likes doit être incrémenté.</param>
void IncrementNbLikes(Titre titre);
/// <summary>
/// Recherche les titres dont le libellé contient le mot spécifié, en ignorant la casse.
/// </summary>
/// <param name="mot">Le mot à rechercher dans les libellés des titres.</param>
/// <returns>Une collection de titres correspondant au critère de recherche, triée par libellé.</returns>
IEnumerable<Titre> Search(string mot);
/// <summary>
/// Recherche les titres associés à un style dont le libellé contient la chaîne spécifiée, en ignorant la casse.
/// </summary>
/// <param name="libelle">Le libellé du style à rechercher dans les titres.</param>
/// <returns>Une collection de titres correspondant au critère de recherche, triée par libellé.</returns>
IEnumerable<Titre> SearchByStyle(string libelle);
/// <summary>
/// Met à jour un titre dans la liste des titres en fonction de son identifiant. Si aucun titre correspondant à l'identifiant du titre fourni n'est trouvé, un message d'avertissement est enregistré dans les logs et aucune mise à jour n'est effectuée.
/// </summary>
/// <param name="titre">L'objet titre à mettre à jour.</param>
void Update(Titre titre);
}
}

View File

@@ -1,29 +0,0 @@
using Webzine.Entity;
namespace Webzine.Repository.Contracts
{
public interface ITitreRepository
{
// void Add(Titre titre);
// int Count();
// void Delete(Titre titre);
Titre? Find(int idTitre);
IEnumerable<Titre> FindTitres(int offset, int limit);
IEnumerable<Titre> FindAll();
// void IncrementNbLectures(Titre titre);
// void IncrementNbLikes(Titre titre);
IEnumerable<Titre> Search(string mot);
IEnumerable<Titre> SearchByStyle(string libelle);
// void Update(Titre titre);
}
}

View File

@@ -0,0 +1,142 @@
namespace Webzine.Repository
{
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Webzine.EntitiesContext;
using Webzine.Entity;
using Webzine.Repository.Contracts;
/// <summary>
/// Initialise une classe <see cref="DbArtisteRepository"/> qui implémente l'interface <see cref="IArtisteRepository"/> pour gérer les opérations de base de données liées aux artistes.
/// Utilise <see cref="IArtisteRepository"/> en injection de dépendances.
/// </summary>
public class DbArtisteRepository : IArtisteRepository
{
private WebzineDbContext _context;
private readonly ILogger<LocalArtisteRepository> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="DbArtisteRepository"/> class.
/// </summary>
/// <param name="context">Le contexte de base de données à utiliser pour accéder aux entités et effectuer des opérations de
/// persistance. Ne peut pas être null.</param>
public DbArtisteRepository(WebzineDbContext context, ILogger<LocalArtisteRepository> logger)
{
this._logger = logger;
this._context = context;
}
/// <inheritdoc/>
public void Add(Artiste artiste)
{
try
{
if (artiste == null)
{
throw new ArgumentNullException(nameof(artiste), "L'artiste à ajouter ne peut pas être null.");
}
this._context.Artistes.Add(artiste);
this._context.SaveChanges();
}
catch (Exception ex)
{
this._logger.LogError(ex, "Une erreur est survenue lors de l'ajout de l'artiste {Nom}.", artiste?.Nom);
throw new Exception("Une erreur est survenue lors de l'ajout de l'artiste.", ex);
}
}
/// <inheritdoc/>
public void Delete(Artiste artiste)
{
try
{
if (artiste == null)
{
throw new ArgumentNullException(nameof(artiste), "L'artiste à supprimer ne peut pas être null.");
}
this._context.Artistes.Remove(artiste);
this._context.SaveChanges();
}
catch (Exception ex)
{
this._logger.LogError(ex, "Une erreur est survenue lors de la suppression de l'artiste {Nom}.", artiste?.Nom);
throw new Exception("Une erreur est survenue lors de la suppression de l'artiste.", ex);
}
}
/// <inheritdoc/>
public Artiste Find(int id)
{
Artiste artiste = this._context.Artistes
.Include(a => a.Titres)
.FirstOrDefault(a => a.IdArtiste == id);
if (artiste == null)
{
this._logger.LogWarning("Aucun artiste trouvé avec l'identifiant {Id}", id);
}
return artiste;
}
/// <inheritdoc/>
public Artiste FindByName(string nom)
{
if (string.IsNullOrWhiteSpace(nom))
{
this._logger.LogWarning("Tentative de recherche avec un nom vide ou null.");
return null;
}
var artiste = this._context.Artistes
.Include(a => a.Titres)
.FirstOrDefault(a => a.Nom == nom);
if (artiste == null)
{
this._logger.LogWarning("Recherche Nom : Aucun artiste trouvé pour '{Nom}'.", nom);
}
return artiste;
}
/// <inheritdoc/>
public IEnumerable<Artiste> FindAll()
{
try
{
// .AsNoTracking() rend la requête beaucoup plus rapide pour de la lecture
var artistes = this._context.Artistes.AsNoTracking().ToList();
this._logger.LogInformation("{Count} artistes récupérés de la base.", artistes.Count);
return artistes;
}
catch (Exception ex)
{
this._logger.LogError(ex, "Erreur lors de la récupération de tous les artistes.");
return Enumerable.Empty<Artiste>(); // Retourne une liste vide au lieu de faire crash l'UI
}
}
/// <inheritdoc/>
public void Update(Artiste artiste)
{
if (artiste == null)
{
throw new ArgumentNullException(nameof(artiste));
}
try
{
this._context.Artistes.Update(artiste);
this._context.SaveChanges();
this._logger.LogInformation("Artiste {Id} ({Nom}) mis à jour avec succès.", artiste.IdArtiste, artiste.Nom);
}
catch (Exception ex)
{
this._logger.LogError(ex, "Erreur lors de la mise à jour de l'artiste {Id}.", artiste.IdArtiste);
throw;
}
}
}
}

View File

@@ -1,69 +0,0 @@
// <copyright file="DbEntityRepository.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace Webzine.Repository
{
using Webzine.EntitiesContext;
using Webzine.Entity;
using Webzine.Entity.Fixtures;
using Webzine.Repository.Contracts;
using Webzine.Repository.Fake;
public class DbEntityRepository
{
private readonly WebzineDbContext context;
/// <summary>
/// Initializes a new instance of the <see cref="DbEntityRepository"/> class.
/// </summary>
public DbEntityRepository(WebzineDbContext context)
{
this.context = context;
}
/// <summary>
/// Seed de la base de données à partir de données générées.
/// </summary>
public void SeedBaseDeDonnees(
int nbArtistes = 100,
int nbTitres = 500,
int minStyles = 15,
int maxStyles = 20,
int minCommentairesParTitre = 0,
int maxCommentairesParTitre = 5)
{
if (this.context.Artistes.Any() ||
this.context.Titres.Any() ||
this.context.Styles.Any() ||
this.context.Commentaires.Any())
{
return;
}
List<Artiste> artistes = ArtisteFactory.CreerListeArtiste(nbArtistes);
List<Style> styles = StyleFactory.CreerListeStyle(minStyles, maxStyles);
this.context.Artistes.AddRange(artistes);
this.context.Styles.AddRange(styles);
this.context.SaveChanges();
List<Titre> titres = TitreFactory.CreerListeTitre(nbTitres, artistes, styles);
this.context.Titres.AddRange(titres);
this.context.SaveChanges();
List<Commentaire> commentaires = new List<Commentaire>();
foreach (Titre titre in titres)
{
commentaires.AddRange(
CommentaireFactory.CreerListeCommentaire(
titre,
minCommentairesParTitre,
maxCommentairesParTitre));
}
this.context.Commentaires.AddRange(commentaires);
this.context.SaveChanges();
}
}
}

View File

@@ -0,0 +1,180 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Webzine.EntitiesContext;
using Webzine.Entity;
using Webzine.Repository.Contracts;
namespace Webzine.Repository;
/// <summary>
/// Classe qui implémente le repository pour les styles en utilisant une base de données.
/// </summary>
public class DbStyleRepository : IStyleRepository
{
private readonly ILogger<DbStyleRepository> logger;
private readonly WebzineDbContext context;
/// <summary>
/// Initializes a new instance of the <see cref="DbStyleRepository"/> class.
/// </summary>
/// <param name="logger">Le service de journalisation injecté pour suivre les opérations du repository.</param>
/// <param name="context">Le contexte de base de données injecté.</param>
public DbStyleRepository(ILogger<DbStyleRepository> logger, WebzineDbContext context)
{
this.logger = logger;
this.context = context;
this.logger.LogDebug(1, "NLog injecté dans DbStyleRepository");
}
/// <inheritdoc/>
public void Add(Style style)
{
try
{
this.logger.LogInformation("Ajout d'un nouveau style: {Libelle}", style.Libelle);
this.logger.LogDebug("Début de l'ajout du style en base de données");
this.context.Styles.Add(style);
this.context.SaveChanges();
this.logger.LogDebug("Style ajouté avec succès avec l'ID: {IdStyle}", style.IdStyle);
}
catch (DbUpdateException ex)
{
this.logger.LogError(ex, "Erreur de base de données lors de l'ajout du style: {Libelle}", style.Libelle);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de l'ajout du style: {Libelle}", style.Libelle);
throw;
}
}
/// <inheritdoc/>
public void Delete(Style style)
{
try
{
this.logger.LogInformation("Suppression du style avec l'ID: {IdStyle}", style.IdStyle);
this.logger.LogDebug("Vérification de l'existence du style en base de données");
// Check if style exists
var existingStyle = this.context.Styles.Find(style.IdStyle);
if (existingStyle == null)
{
this.logger.LogWarning("Style avec l'ID {IdStyle} non trouvé pour la suppression", style.IdStyle);
throw new InvalidOperationException($"Style avec l'ID {style.IdStyle} non trouvé.");
}
this.logger.LogDebug("Style trouvé, suppression en cours");
this.context.Styles.Remove(existingStyle);
this.context.SaveChanges();
this.logger.LogDebug("Style supprimé avec succès: {IdStyle}", style.IdStyle);
}
catch (DbUpdateException ex)
{
this.logger.LogError(ex, "Erreur de base de données lors de la suppression du style ID: {IdStyle}", style.IdStyle);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la suppression du style ID: {IdStyle}", style.IdStyle);
throw;
}
}
/// <inheritdoc/>
public Style Find(int id)
{
try
{
this.logger.LogDebug("Recherche du style avec l'ID: {Id}", id);
if (id <= 0)
{
this.logger.LogWarning("Tentative de recherche d'un style avec un Id invalide: {Id}", id);
return new Style();
}
this.logger.LogDebug("Préparation de la requête avec inclusion des titres");
var style = this.context.Styles
.Include(s => s.Titres)
.FirstOrDefault(s => s.IdStyle == id);
if (style == null)
{
this.logger.LogWarning("Style avec l'ID {Id} non trouvé", id);
style = new Style();
}
else
{
this.logger.LogDebug("Style trouvé: {Libelle}", style.Libelle);
}
return style;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche du style avec l'ID: {Id}", id);
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Style> FindAll()
{
try
{
this.logger.LogDebug("Récupération de tous les styles");
this.logger.LogDebug("Tri des styles par libellé");
var styles = this.context.Styles
.OrderBy(s => s.Libelle)
.ToList();
this.logger.LogDebug("{Count} styles récupérés", styles.Count);
return styles;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la récupération de tous les styles");
throw;
}
}
/// <inheritdoc/>
public void Update(Style style)
{
try
{
this.logger.LogInformation("Mise à jour du style avec l'ID: {IdStyle}", style.IdStyle);
this.logger.LogDebug("Recherche du style en base de données");
var existingStyle = this.context.Styles.Find(style.IdStyle);
if (existingStyle == null)
{
this.logger.LogWarning("Style avec l'ID {IdStyle} non trouvé pour la mise à jour", style.IdStyle);
throw new InvalidOperationException($"Style avec l'ID {style.IdStyle} non trouvé.");
}
// Update properties
this.logger.LogDebug("Style trouvé, mise à jour des propriétés");
existingStyle.Libelle = style.Libelle;
this.context.SaveChanges();
this.logger.LogDebug("Style mis à jour avec succès: {IdStyle}", style.IdStyle);
}
catch (DbUpdateException ex)
{
this.logger.LogError(ex, "Erreur de base de données lors de la mise à jour du style ID: {IdStyle}", style.IdStyle);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la mise à jour du style ID: {IdStyle}", style.IdStyle);
throw;
}
}
}

View File

@@ -0,0 +1,334 @@
using Microsoft.EntityFrameworkCore;
using Webzine.EntitiesContext;
using Microsoft.Extensions.Logging;
using Webzine.Entity;
using Webzine.Repository.Contracts;
namespace Webzine.Repository;
/// <summary>
/// Classe qui implémente le repository pour les titres en utilisant une base de données.
/// </summary>
public class DbTitreRepository : ITitreRepository
{
private readonly ILogger<DbTitreRepository> logger;
private readonly WebzineDbContext context;
/// <summary>
/// Initializes a new instance of the <see cref="DbTitreRepository"/> class.
/// </summary>
/// <param name="logger">Le service de journalisation injecté pour suivre les opérations du repository.</param>
/// <param name="context">Le contexte de base de données injecté.</param>
public DbTitreRepository(ILogger<DbTitreRepository> logger, WebzineDbContext context)
{
this.logger = logger;
this.context = context;
this.logger.LogDebug(1, "NLog injecté dans DbTitreRepository");
}
/// <inheritdoc/>
public void Add(Titre titre)
{
try
{
this.logger.LogInformation("Ajout d'un nouveau titre: {Libelle}", titre.Libelle);
this.logger.LogDebug("Début de l'ajout du titre en base de données");
this.context.Titres.Add(titre);
this.context.SaveChanges();
this.logger.LogDebug("Titre ajouté avec succès avec l'ID: {IdTitre}", titre.IdTitre);
}
catch (DbUpdateException ex)
{
this.logger.LogError(ex, "Erreur de base de données lors de l'ajout du titre: {Libelle}", titre.Libelle);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de l'ajout du titre: {Libelle}", titre.Libelle);
throw;
}
}
/// <inheritdoc/>
public int Count()
{
try
{
this.logger.LogDebug("Comptage des titres en base de données");
var count = this.context.Titres.Count();
this.logger.LogDebug("Nombre total de titres: {Count}", count);
return count;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors du comptage des titres");
throw;
}
}
/// <inheritdoc/>
public void Delete(Titre titre)
{
try
{
this.logger.LogInformation("Suppression du titre avec l'ID: {IdTitre}", titre.IdTitre);
this.logger.LogDebug("Début de la suppression du titre en base de données");
this.context.Titres.Remove(titre);
this.context.SaveChanges();
this.logger.LogDebug("Titre supprimé avec succès: {IdTitre}", titre.IdTitre);
}
catch (DbUpdateException ex)
{
this.logger.LogError(ex, "Erreur de base de données lors de la suppression du titre ID: {IdTitre}", titre.IdTitre);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la suppression du titre ID: {IdTitre}", titre.IdTitre);
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Titre> FindTitres(int offset, int limit)
{
try
{
this.logger.LogDebug("Recherche des titres avec offset: {Offset}, limit: {Limit}", offset, limit);
this.logger.LogDebug("Préparation de la requête avec les inclusions Artiste et Styles");
var titres = this.context.Titres
.Include(t => t.Artiste)
.Include(t => t.Styles)
.OrderBy(t => t.Libelle)
.Skip(offset)
.Take(limit)
.ToList();
this.logger.LogDebug("{Count} titres trouvés", titres.Count);
return titres;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche des titres avec offset: {Offset}, limit: {Limit}", offset, limit);
throw;
}
}
/// <inheritdoc/>
public void IncrementNbLectures(Titre titre)
{
try
{
this.logger.LogInformation("Incrémentation du nombre de lectures pour le titre ID: {IdTitre}", titre.IdTitre);
this.logger.LogDebug("Recherche du titre en base de données");
var existingTitre = this.context.Titres.Find(titre.IdTitre);
if (existingTitre != null)
{
this.logger.LogDebug("Titre trouvé, incrémentation du compteur de lectures");
existingTitre.NbLectures++;
this.context.SaveChanges();
this.logger.LogDebug("Nouveau nombre de lectures: {NbLectures}", existingTitre.NbLectures);
}
else
{
this.logger.LogWarning("Titre avec l'ID {IdTitre} non trouvé pour l'incrémentation des lectures", titre.IdTitre);
}
}
catch (DbUpdateException ex)
{
this.logger.LogError(ex, "Erreur de base de données lors de l'incrémentation des lectures pour le titre ID: {IdTitre}", titre.IdTitre);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de l'incrémentation des lectures pour le titre ID: {IdTitre}", titre.IdTitre);
throw;
}
}
/// <inheritdoc/>
public void IncrementNbLikes(Titre titre)
{
try
{
this.logger.LogInformation("Incrémentation du nombre de likes pour le titre ID: {IdTitre}", titre.IdTitre);
this.logger.LogDebug("Recherche du titre en base de données");
var existingTitre = this.context.Titres.Find(titre.IdTitre);
if (existingTitre != null)
{
this.logger.LogDebug("Titre trouvé, incrémentation du compteur de likes");
existingTitre.NbLikes++;
this.context.SaveChanges();
this.logger.LogDebug("Nouveau nombre de likes: {NbLikes}", existingTitre.NbLikes);
}
else
{
this.logger.LogWarning("Titre avec l'ID {IdTitre} non trouvé pour l'incrémentation des likes", titre.IdTitre);
}
}
catch (DbUpdateException ex)
{
this.logger.LogError(ex, "Erreur de base de données lors de l'incrémentation des likes pour le titre ID: {IdTitre}", titre.IdTitre);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de l'incrémentation des likes pour le titre ID: {IdTitre}", titre.IdTitre);
throw;
}
}
/// <inheritdoc/>
public void Update(Titre titre)
{
try
{
this.logger.LogInformation("Mise à jour du titre avec l'ID: {IdTitre}", titre.IdTitre);
this.logger.LogDebug("Début de la mise à jour du titre en base de données");
var existingTitre = this.context.Titres.Find(titre.IdTitre);
if (existingTitre != null)
{
this.logger.LogDebug("Titre trouvé, mise à jour des propriétés");
this.context.Entry(existingTitre).CurrentValues.SetValues(titre);
// Handle many-to-many relationships
this.logger.LogDebug("Mise à jour des relations many-to-many (Styles)");
this.context.Entry(existingTitre).Collection(t => t.Styles).Load();
existingTitre.Styles.Clear();
foreach (var style in titre.Styles)
{
existingTitre.Styles.Add(style);
}
this.context.SaveChanges();
this.logger.LogDebug("Titre mis à jour avec succès: {IdTitre}", titre.IdTitre);
}
else
{
this.logger.LogWarning("Titre avec l'ID {IdTitre} non trouvé pour la mise à jour", titre.IdTitre);
throw new InvalidOperationException($"Titre avec l'ID {titre.IdTitre} non trouvé.");
}
}
catch (DbUpdateException ex)
{
this.logger.LogError(ex, "Erreur de base de données lors de la mise à jour du titre ID: {IdTitre}", titre.IdTitre);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la mise à jour du titre ID: {IdTitre}", titre.IdTitre);
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Titre> Search(string mot)
{
try
{
this.logger.LogInformation("Recherche des titres avec le mot-clé: {Mot}", mot);
this.logger.LogDebug("Préparation de la requête de recherche avec les inclusions");
var titres = this.context.Titres
.Include(t => t.Artiste)
.Include(t => t.Styles)
.Where(t => t.Libelle.ToLower().Contains(mot.ToLower()))
.OrderBy(t => t.Libelle)
.ToList();
this.logger.LogDebug("{Count} titres trouvés correspondant à '{Mot}'", titres.Count, mot);
return titres;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche des titres avec le mot-clé: {Mot}", mot);
throw;
}
}
/// <inheritdoc/>
public Titre Find(int idTitre)
{
try
{
this.logger.LogDebug("Recherche du titre avec l'ID: {IdTitre}", idTitre);
this.logger.LogDebug("Préparation de la requête avec les inclusions Artiste, Styles et Commentaires");
var titre = this.context.Titres
.Include(t => t.Artiste)
.Include(t => t.Styles)
.Include(t => t.Commentaires)
.First(t => t.IdTitre == idTitre);
this.logger.LogDebug("Titre trouvé: {Libelle}", titre.Libelle);
return titre;
}
catch (InvalidOperationException ex)
{
this.logger.LogWarning(ex, "Aucun titre trouvé avec l'ID: {IdTitre}", idTitre);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche du titre avec l'ID: {IdTitre}", idTitre);
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Titre> FindAll()
{
try
{
this.logger.LogDebug("Récupération de tous les titres");
this.logger.LogDebug("Préparation de la requête avec les inclusions Artiste et Styles");
var titres = this.context.Titres
.Include(t => t.Artiste)
.Include(t => t.Styles)
.OrderBy(t => t.Libelle)
.ToList();
this.logger.LogDebug("{Count} titres récupérés", titres.Count);
return titres;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la récupération de tous les titres");
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Titre> SearchByStyle(string libelle)
{
try
{
this.logger.LogInformation("Recherche des titres par style: {Libelle}", libelle);
this.logger.LogDebug("Préparation de la requête de recherche par style");
var titres = this.context.Titres
.Include(t => t.Artiste)
.Include(t => t.Styles)
.Where(t => t.Styles.Any(s => s.Libelle.ToLower() == libelle.ToLower()))
.OrderBy(t => t.Libelle)
.ToList();
this.logger.LogDebug("{Count} titres trouvés pour le style '{Libelle}'", titres.Count, libelle);
return titres;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche des titres par style: {Libelle}", libelle);
throw;
}
}
}

View File

@@ -0,0 +1,133 @@
namespace Webzine.Repository
{
using Microsoft.Extensions.Logging;
using Webzine.Entity;
using Webzine.Repository.Contracts;
/// <summary>
/// Initialise une classe <see cref="LocalArtisteRepository"/> qui implémente l'interface <see cref="IArtisteRepository"/> pour gérer les opérations de base de données liées aux artistes.
/// Utilise <see cref="IArtisteRepository"/> en injection de dépendances.
/// </summary>
public class LocalArtisteRepository : IArtisteRepository
{
private readonly ILogger<LocalArtisteRepository> _logger;
private readonly List<Artiste> _artistes;
/// <summary>
/// Initializes a new instance of the <see cref="LocalArtisteRepository"/> class.
/// Est liéee à une liste d'artistes en local et utilise un logger pour enregistrer les opérations effectuées sur les artistes.
/// </summary>
/// <param name="artistes">La liste des artistes à initialiser. Ne peut pas être null.</param>
/// <param name="logger">Le logger à utiliser pour enregistrer les messages de journalisation. Ne peut pas être null.</param>
public LocalArtisteRepository(List<Artiste> artistes, ILogger<LocalArtisteRepository> logger)
{
this._logger = logger;
this._artistes = artistes;
}
/// <inheritdoc/>
public void Add(Artiste artiste)
{
try
{
if (artiste == null)
{
this._logger.LogError("L'artiste à ajouter ne peut pas être null.");
throw new ArgumentNullException(nameof(artiste));
}
if (this._artistes.Any(a => a.IdArtiste == artiste.IdArtiste))
{
this._logger.LogWarning("Un artiste avec l'ID {Id} existe déjà. L'ajout est ignoré.", artiste.IdArtiste);
return;
}
this._artistes.Add(artiste);
this._logger.LogInformation("Artiste ajouté : {Nom}", artiste.Nom);
}
catch (Exception ex)
{
this._logger.LogError(ex, "Erreur lors de l'ajout de l'artiste : {Nom}", artiste?.Nom);
throw;
}
}
/// <inheritdoc/>
public void Delete(Artiste artiste)
{
try
{
this._artistes.Remove(artiste);
this._logger.LogInformation("Artiste supprimé : {Nom}", artiste.Nom);
}
catch (Exception ex)
{
this._logger.LogError(ex, "Erreur lors de la suppression de l'artiste : {Nom}", artiste.Nom);
throw;
}
}
/// <inheritdoc/>
public Artiste Find(int id)
{
Artiste artiste = this._artistes.FirstOrDefault(a => a.IdArtiste == id);
if (artiste == null)
{
this._logger.LogWarning("Aucun artiste trouvé avec l'identifiant {Id}", id);
}
return artiste;
}
/// <inheritdoc/>
public Artiste FindByName(string nom)
{
Artiste artiste = this._artistes.FirstOrDefault(a => a.Nom == nom);
if (artiste == null)
{
this._logger.LogWarning("Aucun artiste trouvé avec le nom {Nom}", nom);
}
return artiste;
}
/// <inheritdoc/>
/// La liste retournée est une copie de la liste interne, donc elle ne peut être nulle.
public IEnumerable<Artiste> FindAll()
{
return this._artistes;
}
/// <inheritdoc/>
public void Update(Artiste artiste)
{
if (artiste == null)
{
this._logger.LogError("L'artiste à mettre à jour ne peut pas être null.");
throw new ArgumentNullException(nameof(artiste));
}
try
{
var artisteToUpdate = this._artistes.FirstOrDefault(a => a.IdArtiste == artiste.IdArtiste);
if (artisteToUpdate != null)
{
artisteToUpdate.Nom = artiste.Nom;
artisteToUpdate.Biographie = artiste.Biographie;
artisteToUpdate.Titres = artiste.Titres;
this._logger.LogInformation("Artiste {Id} mis à jour avec succès.", artiste.IdArtiste);
}
else
{
this._logger.LogWarning("Mise à jour impossible : l'artiste avec l'ID {Id} n'existe pas.", artiste.IdArtiste);
throw new KeyNotFoundException($"L'artiste {artiste.IdArtiste} est introuvable.");
}
}
catch (Exception ex)
{
this._logger.LogError(ex, "Une erreur est survenue lors de la mise à jour de l'artiste {Id}.", artiste.IdArtiste);
throw;
}
}
}
}

View File

@@ -1,91 +0,0 @@
using Microsoft.Extensions.Logging;
using Webzine.Entity;
using Webzine.Entity.Fixtures;
using Webzine.Repository.Contracts;
namespace Webzine.Repository;
/// <summary>
/// Classe qui permet d'initialiser un jeu de données
/// pour tester l'application.
/// </summary>
public class LocalEntityRepository : ITitreRepository
{
private readonly ILogger<LocalEntityRepository> _logger;
private readonly List<Titre> _titres;
/// <summary>
/// Initialise une nouvelle instance du <see cref="LocalEntityRepository"/> avec un service de journalisation injecte.
/// </summary>
/// <param name="logger">Service de journalisation injecte pour suivre les operations du repository.</param>
public LocalEntityRepository(ILogger<LocalEntityRepository> logger)
{
this._logger = logger;
this._logger.LogDebug(1, "NLog injected into LocalEntityRepository");
var factory = new DataFactory();
var artistes = factory.GenerateArtists(10);
var styles = factory.GenerateStyles(10);
_titres = factory.GenerateTitres(30, artistes, styles);
factory.GenerateCommentaires(50, _titres);
}
public IEnumerable<Titre> Search(string mot)
{
if (string.IsNullOrWhiteSpace(mot))
{
return Enumerable.Empty<Titre>();
}
return _titres
.Where(t => !string.IsNullOrWhiteSpace(t.Libelle)
&& t.Libelle.Contains(mot, StringComparison.OrdinalIgnoreCase))
.OrderBy(t => t.Libelle)
.ToList();
}
public Titre? Find(int idTitre)
{
return _titres.FirstOrDefault(t => t.IdTitre == idTitre);
}
public IEnumerable<Titre> FindTitres(
int offset,
int limit)
{
return this._titres
.OrderByDescending(t => t.DateCreation)
.Skip((offset - 1) * limit)
.Take(limit)
.ToList();
}
/// <summary>
/// Retourner tous les titres.
/// </summary>
/// <returns>IEnumerable de titre.</returns>
public IEnumerable<Titre> FindAll()
{
return _titres;
}
/// <summary>
/// Rechercher les titres par style.
/// </summary>
/// <param name="libelle">Libelle du style.</param>
/// <returns>IEnumerable de titre.</returns>
public IEnumerable<Titre> SearchByStyle(string libelle)
{
if (string.IsNullOrWhiteSpace(libelle))
{
return Enumerable.Empty<Titre>();
}
return _titres
.Where(t => t.Styles.Any(s => !string.IsNullOrWhiteSpace(s.Libelle)
&& s.Libelle.Contains(libelle, StringComparison.OrdinalIgnoreCase)))
.OrderBy(t => t.Libelle)
.ToList();
}
}

View File

@@ -0,0 +1,135 @@
using Microsoft.Extensions.Logging;
using Webzine.Entity;
using Webzine.Repository.Contracts;
namespace Webzine.Repository;
/// <summary>
/// Classe qui implémente le repository pour les styles en utilisant une liste locale comme source de données.
/// </summary>
public class LocalStyleRepository : IStyleRepository
{
private readonly ILogger<LocalStyleRepository> logger;
private readonly List<Style> styles;
/// <summary>
/// Initializes a new instance of the <see cref="LocalStyleRepository"/> class.
/// </summary>
/// <param name="logger">Le service de journalisation injecté pour suivre les opérations du repository.</param>
/// <param name="styles">La liste de styles à utiliser comme source de données pour le repository.</param>
public LocalStyleRepository(ILogger<LocalStyleRepository> logger, List<Style> styles)
{
this.logger = logger;
this.styles = styles;
this.logger.LogDebug(1, "NLog injecté dans LocalStyleRepository");
}
/// <inheritdoc/>
public void Add(Style style)
{
try
{
this.logger.LogDebug("Ajout du style: {Libelle}", style.Libelle);
this.styles.Add(style);
this.logger.LogDebug("Style ajouté avec succès, ID: {IdStyle}", style.IdStyle);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de l'ajout du style: {Libelle}", style.Libelle);
throw;
}
}
/// <inheritdoc/>
public void Delete(Style style)
{
try
{
this.logger.LogDebug("Suppression du style ID: {IdStyle}", style.IdStyle);
if (!this.styles.Contains(style))
{
this.logger.LogWarning("Le style avec l'identifiant {IdStyle} n'existe pas dans la liste.", style.IdStyle);
}
this.styles.Remove(style);
this.logger.LogDebug("Style supprimé avec succès, ID: {IdStyle}", style.IdStyle);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la suppression du style ID: {IdStyle}", style.IdStyle);
throw;
}
}
/// <inheritdoc/>
public Style Find(int id)
{
try
{
this.logger.LogDebug("Recherche du style avec ID: {Id}", id);
if (id <= 0)
{
this.logger.LogWarning("Tentative de recherche d'un style avec un Id invalide: {Id}", id);
return new Style();
}
Style style = this.styles.First(s => s.IdStyle == id);
this.logger.LogDebug("Style trouvé: {Libelle}", style.Libelle);
return style;
}
catch (InvalidOperationException ex)
{
this.logger.LogWarning(ex, "Aucun style trouvé avec l'ID: {Id}", id);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche du style avec ID: {Id}", id);
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Style> FindAll()
{
try
{
this.logger.LogDebug("Récupération de tous les styles");
var result = this.styles;
this.logger.LogDebug("{Count} styles récupérés", result.Count);
return result;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la récupération de tous les styles");
throw;
}
}
/// <inheritdoc/>
public void Update(Style style)
{
try
{
this.logger.LogDebug("Mise à jour du style ID: {IdStyle}", style.IdStyle);
int index = this.styles.FindIndex(s => s.IdStyle == style.IdStyle);
if (index == -1)
{
this.logger.LogWarning("Aucun style trouvé avec l'identifiant {IdStyle}.", style.IdStyle);
throw new InvalidOperationException($"Aucun style trouvé avec l'identifiant {style.IdStyle}.");
}
this.styles[index] = style;
this.logger.LogDebug("Style mis à jour avec succès, ID: {IdStyle}", style.IdStyle);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la mise à jour du style ID: {IdStyle}", style.IdStyle);
throw;
}
}
}

View File

@@ -0,0 +1,274 @@
using Microsoft.Extensions.Logging;
using Webzine.Entity;
using Webzine.Repository.Contracts;
namespace Webzine.Repository;
/// <summary>
/// Classe qui implémente le repository pour les titres en utilisant une liste locale comme source de données.
/// </summary>
public class LocalTitreRepository : ITitreRepository
{
private readonly ILogger<LocalTitreRepository> logger;
private readonly List<Titre> titres;
/// <summary>
/// Initializes a new instance of the <see cref="LocalTitreRepository"/> class.
/// </summary>
/// <param name="logger">Le service de journalisation injecté pour suivre les opérations du repository.</param>
/// <param name="titres">La liste de titres à utiliser comme source de données pour le repository.</param>
public LocalTitreRepository(ILogger<LocalTitreRepository> logger, List<Titre> titres)
{
this.logger = logger;
this.titres = titres;
this.logger.LogDebug(1, "NLog injecté dans LocalTitreRepository");
}
/// <inheritdoc/>
public void Add(Titre titre)
{
try
{
this.logger.LogDebug("Ajout du titre: {Libelle}", titre.Libelle);
this.titres.Add(titre);
this.logger.LogDebug("Titre ajouté avec succès, ID: {IdTitre}", titre.IdTitre);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de l'ajout du titre: {Libelle}", titre.Libelle);
throw;
}
}
/// <inheritdoc/>
public int Count()
{
try
{
var count = this.titres.Count;
this.logger.LogDebug("Nombre total de titres: {Count}", count);
return count;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors du comptage des titres");
throw;
}
}
/// <inheritdoc/>
public void Delete(Titre titre)
{
try
{
this.logger.LogDebug("Suppression du titre ID: {IdTitre}", titre.IdTitre);
if (!this.titres.Contains(titre))
{
this.logger.LogWarning("Le titre avec l'identifiant {IdTitre} n'existe pas dans la liste.", titre.IdTitre);
}
this.titres.Remove(titre);
this.logger.LogDebug("Titre supprimé avec succès, ID: {IdTitre}", titre.IdTitre);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la suppression du titre ID: {IdTitre}", titre.IdTitre);
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Titre> FindTitres(int offset, int limit)
{
try
{
this.logger.LogDebug("Recherche des titres avec offset: {Offset}, limit: {Limit}", offset, limit);
if (offset < 0 || limit <= 0)
{
this.logger.LogWarning("FindTitres appelé avec offset {Offset} ou limit {Limit} invalide.", offset, limit);
return Enumerable.Empty<Titre>();
}
var result = this.titres.Skip(offset).Take(limit).ToList();
this.logger.LogDebug("{Count} titres trouvés", result.Count);
return result;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche des titres avec offset: {Offset}, limit: {Limit}", offset, limit);
throw;
}
}
/// <inheritdoc/>
public void IncrementNbLectures(Titre titre)
{
try
{
this.logger.LogDebug("Incrémentation du nombre de lectures pour le titre ID: {IdTitre}", titre.IdTitre);
titre.NbLectures++;
this.logger.LogDebug("Nouveau nombre de lectures: {NbLectures}", titre.NbLectures);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de l'incrémentation des lectures pour le titre ID: {IdTitre}", titre.IdTitre);
throw;
}
}
/// <inheritdoc/>
public void IncrementNbLikes(Titre titre)
{
try
{
this.logger.LogDebug("Incrémentation du nombre de likes pour le titre ID: {IdTitre}", titre.IdTitre);
titre.NbLikes++;
this.logger.LogDebug("Nouveau nombre de likes: {NbLikes}", titre.NbLikes);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de l'incrémentation des likes pour le titre ID: {IdTitre}", titre.IdTitre);
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Titre> Search(string mot)
{
try
{
this.logger.LogDebug("Recherche de titres avec le mot-clé: {Mot}", mot);
if (string.IsNullOrWhiteSpace(mot))
{
this.logger.LogWarning("Search appelé avec une chaîne vide ou contenant uniquement des espaces.");
return Enumerable.Empty<Titre>();
}
IEnumerable<Titre> list = this.titres
.Where(t => !string.IsNullOrWhiteSpace(t.Libelle)
&& t.Libelle.Contains(mot, StringComparison.OrdinalIgnoreCase))
.OrderBy(t => t.Libelle)
.ToList();
if (!list.Any())
{
this.logger.LogInformation("Aucun titre trouvé correspondant au terme de recherche '{Mot}'.", mot);
}
else
{
this.logger.LogDebug("{Count} titres trouvés pour le mot-clé '{Mot}'", list.Count(), mot);
}
return list;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche des titres avec le mot-clé: {Mot}", mot);
throw;
}
}
/// <inheritdoc/>
public Titre Find(int idTitre)
{
try
{
this.logger.LogDebug("Recherche du titre avec ID: {IdTitre}", idTitre);
Titre titre = this.titres.First(t => t.IdTitre == idTitre);
this.logger.LogDebug("Titre trouvé: {Libelle}", titre.Libelle);
return titre;
}
catch (InvalidOperationException ex)
{
this.logger.LogWarning(ex, "Aucun titre trouvé avec l'ID: {IdTitre}", idTitre);
throw;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche du titre avec ID: {IdTitre}", idTitre);
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Titre> FindAll()
{
try
{
this.logger.LogDebug("Récupération de tous les titres");
var result = this.titres;
this.logger.LogDebug("{Count} titres récupérés", result.Count);
return result;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la récupération de tous les titres");
throw;
}
}
/// <inheritdoc/>
public IEnumerable<Titre> SearchByStyle(string libelle)
{
try
{
this.logger.LogDebug("Recherche des titres par style: {Libelle}", libelle);
if (string.IsNullOrWhiteSpace(libelle))
{
this.logger.LogWarning("SearchByStyle appelé avec une chaîne vide ou contenant uniquement des espaces.");
return Enumerable.Empty<Titre>();
}
IEnumerable<Titre> list = this.titres
.Where(t => t.Styles.Any(s => !string.IsNullOrWhiteSpace(s.Libelle)
&& s.Libelle.Contains(libelle, StringComparison.OrdinalIgnoreCase)))
.OrderBy(t => t.Libelle)
.ToList();
if (!list.Any())
{
this.logger.LogInformation("Aucun titre trouvé correspondant au style '{Libelle}'.", libelle);
}
else
{
this.logger.LogDebug("{Count} titres trouvés pour le style '{Libelle}'", list.Count(), libelle);
}
return list;
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la recherche des titres par style: {Libelle}", libelle);
throw;
}
}
/// <inheritdoc/>
public void Update(Titre titre)
{
try
{
this.logger.LogDebug("Mise à jour du titre ID: {IdTitre}", titre.IdTitre);
int index = this.titres.FindIndex(t => t.IdTitre == titre.IdTitre);
if (index == -1)
{
this.logger.LogWarning("Aucun titre trouvé avec l'identifiant {IdTitre}.", titre.IdTitre);
throw new InvalidOperationException($"Aucun titre trouvé avec l'identifiant {titre.IdTitre}.");
}
this.titres[index] = titre;
this.logger.LogDebug("Titre mis à jour avec succès, ID: {IdTitre}", titre.IdTitre);
}
catch (Exception ex)
{
this.logger.LogError(ex, "Erreur lors de la mise à jour du titre ID: {IdTitre}", titre.IdTitre);
throw;
}
}
}

View File

@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Webzine.Entity;
using Webzine.Entity.Fixtures;
using Webzine.Repository.Contracts;
using Webzine.WebApplication.Areas.Administration.ViewModels.Artiste;
namespace Webzine.WebApplication.Areas.Administration.Controllers;
@@ -10,16 +11,17 @@ public class ArtisteController : Controller
{
// Injection du logger via le constructeur
private readonly ILogger<ArtisteController> _logger;
private readonly List<Artiste> _artistes;
private readonly IArtisteRepository _artisteRepository;
private readonly List<Artiste> _artistes = new List<Artiste>();
public ArtisteController(ILogger<ArtisteController> logger)
public ArtisteController(ILogger<ArtisteController> logger,
IArtisteRepository artisteRepository)
{
this._logger = logger;
this._logger.LogDebug(1, "initialisation du ArtisteController d'administration");
var factory = new DataFactory();
_artistes = factory.GenerateArtists(10);
this._artisteRepository = artisteRepository;
this._artistes.AddRange(this._artisteRepository.FindAll());
}
/// <summary>
@@ -30,9 +32,7 @@ public class ArtisteController : Controller
public IActionResult Index()
{
var _artistes_ordre = _artistes.OrderBy(t => t.Nom).ToList();
this._logger.LogInformation("Initialisation du contrôleur TitreController pour l'Administration.");
var _artistes_ordre = this._artistes.OrderBy(t => t.Nom).ToList();
return View(_artistes_ordre);
}
@@ -60,7 +60,7 @@ public class ArtisteController : Controller
/// <returns>Redirection.</returns>
public IActionResult Edit(int id)
{
var artiste = _artistes.First(t => t.IdArtiste == id);
var artiste = this._artistes.First(t => t.IdArtiste == id);
var model = new AdminArtisteForm
{
@@ -79,7 +79,7 @@ public class ArtisteController : Controller
/// <returns>Redirection.></returns>
public IActionResult Delete(int id)
{
var artiste = _artistes.First(t => t.IdArtiste == id);
var artiste = this._artistes.First(t => t.IdArtiste == id);
var model = new AdminArtisteForm
{
Id = id,

View File

@@ -12,6 +12,7 @@ namespace Webzine.WebApplication.Areas.Administration.Controllers
private readonly List<Commentaire> _commentaires;
/// <summary>
/// Initialise une nouvelle instance de la classe <see cref="CommentaireController"/>.
/// Initialise une nouvelle instance du <see cref="CommentaireController"/>.
/// Les données sont générées dynamiquement via <see cref="DataFactory"/>.
/// </summary>

View File

@@ -1,6 +1,8 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Webzine.Entity;
using Webzine.Entity.Fixtures;
using Webzine.Repository.Contracts;
using Webzine.WebApplication.Areas.Administration.ViewModels;
namespace Webzine.WebApplication.Areas.Administration.Controllers;
@@ -8,31 +10,24 @@ namespace Webzine.WebApplication.Areas.Administration.Controllers;
[Area("Administration")]
public class DashboardController : Controller
{
private readonly ILogger<DashboardController> _logger;
private readonly List<Titre> _titres;
private readonly List<Style> _styles;
private readonly List<Artiste> _artistes;
private readonly ILogger<DashboardController> logger;
private readonly IStyleRepository styleRepository;
private readonly IArtisteRepository artisteRepository;
private readonly ITitreRepository titreRepository;
/// <summary>
/// Initialise une nouvelle instance du <see cref="DashboardController"/>.
/// Les données sont générées dynamiquement via <see cref="DataFactory"/>.
/// Initialise une nouvelle instance de la classe <see cref="DashboardController"/>.
/// </summary>
/// <param name="logger">Service de journalisation injecté.</param>
public DashboardController(ILogger<DashboardController> logger)
/// <param name="styleRepository">Repository des styles injecté.</param>
public DashboardController(ILogger<DashboardController> logger, IStyleRepository styleRepository, IArtisteRepository artisteRepository, ITitreRepository titreRepository)
{
this._logger = logger;
this.logger = logger;
this.styleRepository = styleRepository;
this.artisteRepository = artisteRepository;
this.titreRepository = titreRepository;
this._logger.LogInformation("Initialisation du contrôleur TitreController.");
var factory = new DataFactory();
_artistes = factory.GenerateArtists(10);
_styles = factory.GenerateStyles(10);
_titres = factory.GenerateTitres(30, _artistes, _styles);
factory.GenerateCommentaires(50, _titres);
this._logger.LogInformation("Données fictives générées avec succès.");
this.logger.LogInformation("Initialisation du contrôleur TitreController.");
}
/// <summary>
@@ -41,42 +36,42 @@ public class DashboardController : Controller
/// <returns>La vue Index du tableau de bord.</returns>
public IActionResult Index()
{
var artisteLePlusChronique = _titres
var artisteLePlusChronique = this.titreRepository.FindAll()
.GroupBy(t => t.Artiste)
.OrderByDescending(g => g.Count())
.FirstOrDefault();
.First();
var albumLePlusChronique = _titres
var albumLePlusChronique = this.titreRepository.FindAll()
.GroupBy(t => t.Artiste)
.OrderByDescending(g => g.Select(t => t.Album).Distinct().Count())
.FirstOrDefault();
.First();
var musiqueLaPlusJouee = _titres
var musiqueLaPlusJouee = this.titreRepository.FindAll()
.OrderByDescending(t => t.NbLectures)
.FirstOrDefault();
.First();
var model = new DashboardViewModel
{
NombreArtistes = _artistes.Count,
NombreArtistes = this.artisteRepository.FindAll().Count(),
ArtisteLePlusChronique = artisteLePlusChronique?.Key.Nom,
ArtisteLePlusChronique = artisteLePlusChronique.Key.Nom,
AlbumLePlusChronique = albumLePlusChronique?.Key.Nom,
AlbumLePlusChronique = albumLePlusChronique.Key.Nom,
NombreBiographies = _artistes.Count(a => !string.IsNullOrEmpty(a.Biographie)),
NombreBiographies = this.artisteRepository.FindAll().Count(a => !string.IsNullOrEmpty(a.Biographie)),
IdMusiqueLaPlusJouee = musiqueLaPlusJouee?.IdTitre ?? 0,
MusiqueLaPlusJouee = musiqueLaPlusJouee?.Libelle,
IdMusiqueLaPlusJouee = musiqueLaPlusJouee.IdTitre,
MusiqueLaPlusJouee = musiqueLaPlusJouee.Libelle,
NombreTitres = _titres.Count,
NombreTitres = this.titreRepository.Count(),
NombreGenres = _styles.Count,
NombreGenres = this.styleRepository.FindAll().Count(),
NombreLectures = _titres.Sum(t => t.NbLectures),
NombreLectures = this.titreRepository.FindAll().Sum(t => t.NbLectures),
NombreLikes = _titres.Sum(t => t.NbLikes)
NombreLikes = this.titreRepository.FindAll().Sum(t => t.NbLikes),
};
return View(model);
return this.View(model);
}
}

View File

@@ -1,70 +1,62 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Webzine.Entity;
using Webzine.Entity.Fixtures;
using Webzine.Repository.Contracts;
using Webzine.WebApplication.Areas.Administration.ViewModels.Style;
namespace Webzine.WebApplication.Areas.Administration.Controllers
{
/// <summary>
/// Contrôleur pour la gestion des styles dans l'administration du webzine.
/// </summary>
[Area("Administration")]
public class StyleController : Controller
{
private readonly ILogger<StyleController> _logger;
private readonly List<Style> _styles;
private readonly ILogger<StyleController> logger;
private readonly IStyleRepository styles;
/// <summary>
/// Initialise une nouvelle instance du <see cref="StyleController"/>.
/// Les données sont générées dynamiquement via <see cref="DataFactory"/>.
/// Initialise une nouvelle instance de la classe <see cref="StyleController"/>.
/// </summary>
/// <param name="logger">Service de journalisation injecté.</param>
public StyleController(ILogger<StyleController> logger)
/// <param name="styles">Repository des styles injecté.</param>
public StyleController(ILogger<StyleController> logger, IStyleRepository styles)
{
this._logger = logger;
this.logger = logger;
this._logger.LogInformation("Initialisation du contrôleur StyleController.");
this.logger.LogInformation("Initialisation du contrôleur StyleController.");
var factory = new DataFactory();
_styles = factory.GenerateStyles(10);
this._logger.LogInformation("Données fictives générées avec succès.");
this.styles = styles;
}
// GET: Administration/Styles
/// <summary>
/// Affiche la liste des styles dans la vue Index.
/// </summary>
/// <returns>La vue Index avec le ViewModel contenant la liste des styles.</returns>
public IActionResult Index()
{
// Création de données "bouchon" (mock) pour tester l'affichage
var listeStyles = this._styles;
var listeStyles = this.styles.FindAll().Take(10);
// Initialisation du ViewModel
var viewModel = new StyleViewModel
{
Styles = listeStyles,
};
return View(viewModel);
return this.View(listeStyles);
}
// GET: Administration/Styles/Create
/// <summary>
/// Affiche la vue de création d'un nouveau style.
/// </summary>
/// <returns>La vue Create pour ajouter un nouveau style.</returns>
public IActionResult Create()
{
return View();
return this.View();
}
// GET: Administration/Styles/Delete/5
/// <summary>
/// Affiche la vue de confirmation de suppression d'un style, en récupérant les détails du style à supprimer à partir de l'identifiant fourni.
/// </summary>
/// <param name="id">L'identifiant du style à supprimer.</param>
/// <returns>La vue de confirmation de suppression avec le ViewModel contenant les détails du style à supprimer, ou une redirection vers l'index si le style n'existe pas.</returns>
public IActionResult Delete(int id)
{
var style = this._styles
.FirstOrDefault(c => c.IdStyle == id);
if (style == null)
{
this._logger.LogWarning("Style avec ID {Id} introuvable pour suppression.", id);
return RedirectToAction("Index");
}
var style = this.styles.Find(id);
var vm = new StyleDeleteViewModel
{
@@ -72,30 +64,26 @@ namespace Webzine.WebApplication.Areas.Administration.Controllers
Libelle = style.Libelle,
};
return View(vm);
return this.View(vm);
}
// GET: Administration/Styles/Edit/5
/// <summary>
/// Affiche la vue d'édition d'un style existant, en récupérant les détails du style à éditer à partir de l'identifiant fourni.
/// </summary>
/// <param name="id">L'identifiant du style à éditer.</param>
/// <returns>La vue d'édition avec le ViewModel contenant les détails du style à éditer, ou une redirection vers l'index si le style n'existe pas.</returns>
[HttpGet]
public IActionResult Edit(int id)
{
// Recherche du style (simulation avec la liste _styles)
var style = _styles.FirstOrDefault(s => s.IdStyle == id);
var style = styles.Find(id);
if (style == null)
{
this._logger.LogWarning("Style avec ID {Id} introuvable pour style.", id);
return RedirectToAction("Index");
}
// Mapping vers le ViewModel
var model = new StyleEditViewModel
{
IdStyle = style.IdStyle,
Libelle = style.Libelle
Libelle = style.Libelle,
};
return View(model);
return this.View(model);
}
}
}

View File

@@ -2,39 +2,39 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Webzine.Entity;
using Webzine.Entity.Fixtures;
using Webzine.Repository.Contracts;
using Webzine.WebApplication.Areas.Administration.ViewModels.Titre;
namespace Webzine.WebApplication.Areas.Administration.Controllers;
/// <summary>
/// Contrôleur pour la gestion des titres en administration. Ce contrôleur gère les opérations de création, modification, suppression et affichage des titres dans l'interface d'administration du webzine. Les données sont générées dynamiquement à l'aide de la classe <see cref="DataFactory"/> pour simuler un environnement de développement sans accès à une base de données réelle. Chaque action du contrôleur prépare un ViewModel spécifique pour la vue correspondante, permettant ainsi une séparation claire entre la logique métier et la présentation des données.
/// </summary>
[Area("Administration")]
public class TitreController : Controller
{
private readonly ILogger<TitreController> _logger;
private readonly List<Titre> _titres;
private readonly List<Style> _styles;
private readonly List<Artiste> _artistes;
private readonly ILogger<TitreController> logger;
private readonly ITitreRepository titreRepository;
private readonly IArtisteRepository artisteRepository;
private readonly IStyleRepository styleRepository;
/// <summary>
/// Initialise une nouvelle instance du <see cref="TitreController"/>.
/// Les données sont générées dynamiquement via <see cref="DataFactory"/>.
/// Initialise une nouvelle instance de la classe <see cref="TitreController"/>.
/// </summary>
/// <param name="logger">Service de journalisation injecté.</param>
public TitreController(ILogger<TitreController> logger)
/// <param name="titreRepository">Repository des titres injecté pour accéder aux données des titres.</param>
/// <param name="artisteRepository">Repository des artistes injecté pour accéder aux données des artistes, nécessaires pour les associations avec les titres.</param>
/// <param name="styleRepository">Repository des styles injecté pour accéder aux données des styles, nécessaires pour les associations avec les titres.</param>
public TitreController(ILogger<TitreController> logger, ITitreRepository titreRepository, IArtisteRepository artisteRepository, IStyleRepository styleRepository)
{
this._logger = logger;
this.logger = logger;
this._logger.LogInformation("Initialisation du contrôleur TitreController pour l'Administration.");
this.logger.LogInformation("Initialisation du contrôleur TitreController pour l'Administration.");
var factory = new DataFactory();
_artistes = factory.GenerateArtists(10);
_styles = factory.GenerateStyles(10);
_titres = factory.GenerateTitres(30, _artistes, _styles);
factory.GenerateCommentaires(50, _titres);
this._logger.LogInformation("Données fictives générées avec succès.");
this.titreRepository = titreRepository;
this.artisteRepository = artisteRepository;
this.styleRepository = styleRepository;
}
/// <summary>
@@ -43,19 +43,19 @@ public class TitreController : Controller
/// <returns>La vue Index avec le ViewModel contenant la liste des titres.</returns>
public IActionResult Index()
{
var model = _titres.Select(t => new AdminTitreList
var model = this.titreRepository.FindAll().Take(10).Select(t => new AdminTitreList
{
Id = t.IdTitre,
Artiste = t.Artiste?.Nom,
Artiste = t.Artiste.Nom,
Titre = t.Libelle,
Duree = TimeSpan.FromSeconds(t.Duree).ToString(@"mm\:ss"),
DateSortie = t.DateSortie,
NbLectures = t.NbLectures,
NbLikes = t.NbLikes,
NbCommentaires = t.Commentaires?.Count ?? 0
NbCommentaires = t.Commentaires.Count,
}).ToList();
return View(model);
return this.View(model);
}
/// <summary>
@@ -66,20 +66,20 @@ public class TitreController : Controller
{
var model = new AdminTitreForm
{
Artistes = _artistes.Select(a => new SelectListItem
Artistes = this.artisteRepository.FindAll().Select(a => new SelectListItem
{
Value = a.IdArtiste.ToString(),
Text = a.Nom
Text = a.Nom,
}).ToList(),
AllStyles = _styles.Select(s => new SelectListItem
AllStyles = this.styleRepository.FindAll().Select(s => new SelectListItem
{
Value = s.IdStyle.ToString(),
Text = s.Libelle
}).ToList()
Text = s.Libelle,
}).ToList(),
};
return View(model);
return this.View(model);
}
/// <summary>
@@ -89,7 +89,7 @@ public class TitreController : Controller
/// <returns>La vue Edit avec le ViewModel contenant les données du titre à modifier, ainsi que les listes déroulantes pour les artistes et les styles. </returns>
public IActionResult Edit(int id)
{
var titre = _titres.First(t => t.IdTitre == id);
var titre = this.titreRepository.Find(id);
var model = new AdminTitreForm
{
@@ -106,20 +106,20 @@ public class TitreController : Controller
NbLikes = titre.NbLikes,
Styles = titre.Styles.Select(s => s.IdStyle).ToList(),
Artistes = _artistes.Select(a => new SelectListItem
Artistes = this.artisteRepository.FindAll().Select(a => new SelectListItem
{
Value = a.IdArtiste.ToString(),
Text = a.Nom
Text = a.Nom,
}).ToList(),
AllStyles = _styles.Select(s => new SelectListItem
AllStyles = this.styleRepository.FindAll().Select(s => new SelectListItem
{
Value = s.IdStyle.ToString(),
Text = s.Libelle
}).ToList()
Text = s.Libelle,
}).ToList(),
};
return View(model);
return this.View(model);
}
/// <summary>
@@ -129,15 +129,15 @@ public class TitreController : Controller
/// <returns>La vue de confirmation de suppression avec le ViewModel contenant les détails du titre à supprimer.</returns>
public IActionResult Delete(int id)
{
var titre = _titres.First(t => t.IdTitre == id);
var titre = this.titreRepository.Find(id);
var model = new AdminTitreDelete
{
Id = titre.IdTitre,
Titre = titre.Libelle,
Artiste = titre.Artiste?.Nom
Artiste = titre.Artiste.Nom,
};
return View(model);
return this.View(model);
}
}

View File

@@ -1,17 +0,0 @@
// <copyright file="StyleViewModel.cs" company="Webzine">
// Copyright (c) Webzine. Tout droit réservé.
// </copyright>
namespace Webzine.WebApplication.Areas.Administration.ViewModels.Style
{
/// <summary>
/// ViewModel pour afficher la liste des commentaires en administration.
/// </summary>
public class StyleViewModel
{
/// <summary>
/// Obtient ou définit la liste des commentaires.
/// </summary>
public IEnumerable<Entity.Style> Styles { get; set; } = new List<Entity.Style>();
}
}

View File

@@ -1,4 +1,4 @@
@model Webzine.WebApplication.Areas.Administration.ViewModels.Style.StyleViewModel
@model IEnumerable<Webzine.Entity.Style>
@{
ViewData["Title"] = "Styles";
@@ -24,9 +24,9 @@
</tr>
</thead>
<tbody>
@if (Model.Styles != null && Model.Styles.Any())
@if ( Model.Any())
{
@foreach (Webzine.Entity.Style style in Model.Styles)
@foreach (Webzine.Entity.Style style in Model)
{
<tr class="align-middle">
<td class="p-2">

View File

@@ -2,6 +2,8 @@
// Copyright (c) Equipe 1 - . All rights reserved.
// </copyright>
using Webzine.Repository.Contracts;
namespace Webzine.WebApplication.Controllers
{
using Microsoft.AspNetCore.Mvc;
@@ -30,6 +32,7 @@ namespace Webzine.WebApplication.Controllers
{
this.logger = logger;
this.configuration = configuration;
this.titreRepository = titreRepository;
this.logger.LogDebug(1, "initialisation du AccueilController");
this.titreRepository = titreRepository;
}

View File

@@ -4,26 +4,16 @@ namespace Webzine.WebApplication.Controllers;
public class ApiController : ControllerBase
{
private readonly ILogger<ApiController> _logger;
private readonly ILogger<ApiController> logger;
/// <summary>
/// Initialise une nouvelle instance du <see cref="ApiController"/> avec un service de journalisation injecté.
/// Initialise une nouvelle instance de la classe <see cref="ApiController"/>.
/// </summary>
/// <param name="logger">Service de journalisation injecté pour enregistrer les événements et les erreurs.</param>
public ApiController(ILogger<ApiController> logger)
{
this._logger = logger;
this._logger.LogDebug(1, "initialisation du ApiController");
}
/// <summary>
/// Endpoint de test pour vérifier que l'API fonctionne correctement. Retourne une chaîne de caractères "Hello World !".
/// </summary>
/// <returns>Une chaîne de caractères "Hello World !".</returns>
[HttpGet]
public string HelloWorld()
{
return "Hello World !";
this.logger = logger;
this.logger.LogDebug(1, "initialisation du ApiController");
}
/// <summary>
@@ -33,7 +23,7 @@ public class ApiController : ControllerBase
[HttpGet]
public IActionResult Version()
{
this._logger.LogInformation("Get Version was called");
this.logger.LogInformation("Get Version was called");
return Ok(new
{

View File

@@ -1,21 +1,26 @@
using Microsoft.AspNetCore.Mvc;
using Webzine.Entity.Fixtures;
namespace Webzine.WebApplication.Controllers
namespace Webzine.WebApplication.Controllers
{
using Microsoft.AspNetCore.Mvc;
using Webzine.Entity.Fixtures;
using Webzine.Repository.Contracts;
using Webzine.WebApplication.ViewModels.Artiste;
public class ArtisteController : Controller
{
// Injection du logger via le constructeur
private readonly ILogger<ArtisteController> _logger;
private readonly IArtisteRepository _artisteRepository;
/// <summary>
/// Initialise une nouvelle instance du <see cref="ArtisteController"/> avec un service de journalisation injecté.
/// Initialise une nouvelle instance du <see cref="ArtisteController"/>. avec un service de journalisation injecté.
/// </summary>
/// <param name="logger">Service de journalisation injecté pour enregistrer les événements et les erreurs.</param>
public ArtisteController(ILogger<ArtisteController> logger)
public ArtisteController(ILogger<ArtisteController> logger,
IArtisteRepository artisteRepository)
{
this._logger = logger;
this._logger.LogDebug(1, "initialisation du ArtisteController");
this._logger.LogDebug("Initialisation du ArtisteController");
this._artisteRepository = artisteRepository;
}
/// <summary>
@@ -26,12 +31,12 @@ namespace Webzine.WebApplication.Controllers
[HttpGet("/artiste/{nom}")]
public IActionResult Index(string nom)
{
this._logger.LogInformation("Tentative d'accès à l'artiste avec le nom : {NomArtiste}", nom);
this.logger.LogInformation("Tentative d'accès à l'artiste avec le nom : {NomArtiste}", nom);
if (string.IsNullOrEmpty(nom))
{
this._logger.LogWarning("Nom de l'artiste manquant dans la requête.");
return RedirectToAction("Index", "Accueil");
return RedirectToAction("Index");
}
// On transforme "fatal-bazooka" en "Fatal Bazooka" pour la factory
@@ -39,17 +44,28 @@ namespace Webzine.WebApplication.Controllers
.ToTitleCase(nom.Replace("-", " "));
// On appelle la factory pour obtenir l'artiste unique
var artiste = ArtisteFactory.SeedArtisteByName(nomPropre);
var artiste = this._artisteRepository.FindByName(nomPropre);
if (artiste == null)
{
this._logger.LogWarning("Artiste non trouvé pour le nom : {NomArtiste}", nomPropre);
return RedirectToAction("Index");
}
var viewModel = new ArtisteDetailsViewModel
{
IdArtiste = artiste.IdArtiste,
Nom = artiste.Nom,
Biographie = artiste.Biographie,
// On effectue le groupement ici une bonne fois pour toutes
AlbumsGroupes = artiste.Titres
.OrderBy(t => t.Libelle)
.GroupBy(t => t.Album)
.OrderBy(g => g.Key),
};
this._logger.LogInformation("Artiste trouvé : {NomArtiste}", nom);
return View(artiste);
return View(viewModel);
}
}
}

View File

@@ -8,16 +8,16 @@ namespace Webzine.WebApplication.Controllers
public class ContactController : Controller
{
// Injection du logger via le constructeur
private readonly ILogger<ContactController> _logger;
private readonly ILogger<ContactController> logger;
/// <summary>
/// Initialise une nouvelle instance du <see cref="ContactController"/> avec un service de journalisation injecté.
/// Initialise une nouvelle instance de la classe <see cref="ContactController"/>.
/// </summary>
/// <param name="logger">Service de journalisation injecté pour enregistrer les événements et les erreurs.</param>
public ContactController(ILogger<ContactController> logger)
{
this._logger = logger;
this._logger.LogDebug(1, "initialisation du ContactController");
this.logger = logger;
this.logger.LogDebug(1, "initialisation du ContactController");
}
/// <summary>
@@ -26,7 +26,7 @@ namespace Webzine.WebApplication.Controllers
/// <returns>La vue Index de la page de contact.</returns>
public IActionResult Index()
{
return View();
return this.View();
}
}
}

View File

@@ -17,7 +17,7 @@ public class TitreController : Controller
private readonly ITitreRepository titreRepository;
/// <summary>
/// Initialise une nouvelle instance du <see cref="TitreController"/>.
/// Initialise une nouvelle instance de la classe <see cref="TitreController"/>.
/// </summary>
/// <param name="logger">Service de journalisation injecte.</param>
/// <param name="titreRepository">Repository des titres injecte.</param>
@@ -58,7 +58,7 @@ public class TitreController : Controller
NbLikes = titre.NbLikes,
UrlJaquette = titre.UrlJaquette,
UrlEcoute = titre.UrlEcoute,
ArtisteNom = titre.Artiste?.Nom,
ArtisteNom = titre.Artiste.Nom,
Styles = titre.Styles,
Commentaires = titre.Commentaires,
},
@@ -81,7 +81,11 @@ public class TitreController : Controller
{
this.logger.LogInformation("Recherche des titres pour le style : {Style}.", style);
<<<<<<< HEAD
var titresFiltres = this.titreRepository.SearchByStyle(style).ToList();
=======
var titresFiltres = this._titreRepository.SearchByStyle(style).ToList();
>>>>>>> origin/j2/refactor/controler-style-titre
var vm = new TitreStyle
{
@@ -106,7 +110,11 @@ public class TitreController : Controller
if (titre == null)
{
<<<<<<< HEAD
this.logger.LogWarning("Impossible d'ajouter un like. Titre ID {Id} introuvable.", model.IdTitre);
=======
this._logger.LogWarning("Impossible d'ajouter un like. Titre ID {Id} introuvable.", model.IdTitre);
>>>>>>> origin/j2/refactor/controler-style-titre
return this.RedirectToAction("Index");
}
@@ -125,7 +133,11 @@ public class TitreController : Controller
{
if (!this.ModelState.IsValid)
{
<<<<<<< HEAD
this.logger.LogWarning("Echec de validation du modele de commentaire pour le titre ID {Id}.", model.IdTitre);
=======
this._logger.LogWarning("Echec de validation du modele de commentaire pour le titre ID {Id}.", model.IdTitre);
>>>>>>> origin/j2/refactor/controler-style-titre
return this.RedirectToAction("Details", new { id = model.IdTitre });
}
@@ -133,7 +145,11 @@ public class TitreController : Controller
if (titre == null)
{
<<<<<<< HEAD
this.logger.LogWarning("Impossible d'ajouter le commentaire. Titre ID {Id} introuvable.", model.IdTitre);
=======
this._logger.LogWarning("Impossible d'ajouter le commentaire. Titre ID {Id} introuvable.", model.IdTitre);
>>>>>>> origin/j2/refactor/controler-style-titre
return this.RedirectToAction("Index");
}

View File

@@ -31,18 +31,49 @@ try
builder.Services.AddDbContext<WebzineDbContext>(options =>
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));
// Ajout d'un seeder pour la base de données
// Ajout d'un seeder pour la base de donn<EFBFBD>es
builder.Services.AddScoped<DbEntityRepository>();
// NLog: Setup NLog for Dependency injection
builder.Logging.ClearProviders();
builder.Host.UseNLog();
// En fonction de la configuration, utilise soit les repositories basés sur une base de données, soit les repositories basés sur des listes locales.
bool useDatabase = builder.Configuration.GetValue<bool>("UseDatabase");
if (useDatabase)
{
builder.Services.AddScoped<ITitreRepository, DbTitreRepository>();
builder.Services.AddScoped<IStyleRepository, DbStyleRepository>();
builder.Services.AddScoped<IArtisteRepository, DbArtisteRepository>();
//builder.Services.AddScoped<ICommentaireRepository, DbCommentaireRepository>();
}
else
{
builder.Services.AddScoped<ITitreRepository, LocalTitreRepository>();
builder.Services.AddScoped<IStyleRepository, LocalStyleRepository>();
builder.Services.AddScoped<IArtisteRepository, LocalArtisteRepository>();
//builder.Services.AddScoped<ICommentaireRepository, LocalCommentaireRepository>();
}
// https://learn.microsoft.com/fr-fr/aspnet/core/performance/response-compression?view=aspnetcore-10.0#configuration
// Ajoute le service de compression des réponses HTTP pour réduire la taille des données envoyées au client et améliorer les performances de l'application.
builder.Services.AddResponseCompression();
var app = builder.Build();
app.UseResponseCompression();
// Active la possibilite de servir des fichiers statiques presents dans
// le dossier wwwroot.
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
// https://learn.microsoft.com/fr-fr/aspnet/core/fundamentals/static-files?view=aspnetcore-10.0#set-http-response-headers
ctx.Context.Response.Headers.Append("Cache-Control", "public, max-age=31536000");
},
});
using (var scope = app.Services.CreateScope())
{
@@ -71,12 +102,12 @@ try
}
catch (Exception exception)
{
// NLog: attrape les exceptions non gerees et les logge.
// NLog: attrape les exceptions non gerees et les logger.
logger.Error(exception, "Stopped program because of exception");
throw;
}
finally
{
// Assure que NLog flush tous les messages de log avant de fermer l'application.
NLog.LogManager.Shutdown();
LogManager.Shutdown();
}

View File

@@ -0,0 +1,30 @@
namespace Webzine.WebApplication.ViewModels.Artiste
{
using Webzine.Entity;
/// <summary>
/// ViewModel pour afficher les informations d'un artiste et ses titres groupés par album.
/// </summary>
public class ArtisteDetailsViewModel
{
/// <summary>
/// Obtient ou définit l'identifiant de l'artiste.
/// </summary>
public int IdArtiste { get; set; }
/// <summary>
/// Obtient ou définit le nom de l'artiste.
/// </summary>
public string Nom { get; set; } = string.Empty;
/// <summary>
/// Obtient ou définit la biographie de l'artiste.
/// </summary>
public string Biographie { get; set; } = string.Empty;
/// <summary>
/// Obtient ou définit défini la liste des titres de l'artiste groupés par nom d'Album.
/// </summary>
public IEnumerable<IGrouping<string?, Titre>> AlbumsGroupes { get; set; }
= Enumerable.Empty<IGrouping<string?, Titre>>();
}
}

View File

@@ -14,7 +14,8 @@
<div class="col-12 col-md-3 text-center mb-3 mb-md-0">
<img class="img-fluid img-thumbnail"
src="@titre.UrlJaquette"
alt="@titre.Libelle" />
alt="@titre.Libelle"
loading="lazy" />
</div>
<!-- Contenu -->
@@ -82,7 +83,7 @@
{
<div class="col-12 col-md-6 col-lg-4">
<div class="card h-100">
<img class="card-img-top" src="@titre.UrlJaquette" alt="@titre.Album" />
<img class="card-img-top" src="@titre.UrlJaquette" alt="@titre.Album" loading="lazy" />
<div class="card-body">
<a asp-controller="Titre" asp-action="Details" asp-route-id="@titre.IdTitre" class="card-link">

View File

@@ -1,4 +1,4 @@
@model Webzine.Entity.Artiste
@model Webzine.WebApplication.ViewModels.Artiste.ArtisteDetailsViewModel;
@{
ViewData["Title"] = "Artiste";
@@ -8,22 +8,20 @@
<div class="container">
<h1>@Model.Nom</h1>
<hr class="mb-5" />
<hr/>
<p class="lead">@Model.Biographie</p>
<h2 class="mt-5 mb-4">Albums</h2>
<hr class="mb-5" />
<hr/>
@* On groupe les titres par nom d'album *@
@{
var albumsGroupes = Model.Titres
.OrderBy(t => t.Libelle) // Trie les titres par ordre alphabétique au sein de chaque groupe futur
.GroupBy(t => t.Album) // Groupe par nom d'album
.OrderBy(g => g.Key); // Trie les albums par ordre alphabétique (la clé du groupe)
@if (!Model.AlbumsGroupes.Any())
{
<p>Cet artiste n'a pas encore de titres répertoriés.</p>
}
@foreach (var groupe in albumsGroupes)
else
{
@foreach (var groupe in Model.AlbumsGroupes)
{
// On récupère le premier titre du groupe pour afficher l'image de l'album
var premierTitre = groupe.First();
@@ -32,7 +30,8 @@
<div class="col-md-3 mb-3">
<img src="@premierTitre.UrlJaquette"
class="img-fluid shadow-sm rounded border"
alt="Pochette de @groupe.Key" />
alt="Pochette de @groupe.Key"
loading="lazy" />
</div>
<div class="col-md-9">
@@ -70,4 +69,5 @@
</div>
</div>
}
}
</div>

View File

@@ -53,7 +53,7 @@
asp-action="Details"
asp-route-id="@titre.IdTitre"
class="me-3 text-black">
<img src="@titre.UrlJaquette" alt="@titre.Libelle" width="70" height="70" class="object-fit-cover" />
<img src="@titre.UrlJaquette" alt="@titre.Libelle" width="70" height="70" class="object-fit-cover" loading="lazy"/>
</a>
<div class="justify-content-center d-flex flex-column">

View File

@@ -9,8 +9,6 @@
<link rel="stylesheet" href="~/css/bootstrap.min.css">
<link rel="stylesheet" href="~/css/all.min.css">
<link rel="stylesheet" href="~/css/app.css">
<script src="~/js/bootstrap.bundle.js" defer></script>
</head>
<body>
<partial name="_Header"/>
@@ -28,3 +26,5 @@
<partial name="_Footer" />
</body>
</html>
<script src="~/js/bootstrap.bundle.min.js" defer></script>

View File

@@ -86,7 +86,9 @@
<div class="col-md-4 text-center">
<img src="@Model.Details.UrlJaquette"
class="img-fluid rounded shadow"
alt="Jaquette" />
alt="Jaquette"
loading="lazy"
fetchpriority="high" />
</div>
</div>

View File

@@ -29,7 +29,7 @@
<a asp-action="Details"
asp-route-id="@titre.IdTitre"
class="me-3 text-black">
<img src="@titre.UrlJaquette" alt="@titre.Libelle" width="70px" height="70px" class="object-fit-cover"/>
<img src="@titre.UrlJaquette" alt="@titre.Libelle" width="70px" height="70px" class="object-fit-cover" loading="lazy"/>
</a>
<!-- Infos -->

View File

@@ -18,8 +18,6 @@
<ItemGroup>
<Folder Include="Data\" />
<Folder Include="wwwroot\data\" />
<Folder Include="wwwroot\lib\" />
</ItemGroup>
<ItemGroup>

View File

@@ -10,6 +10,7 @@
"NombreDerniereChronique": 3,
"NombreDeTopTitres": 3
},
"UseDatabase": true,
"ConnectionStrings": {
"DefaultConnection": "Data Source=Data/webzine.sqlite"
},

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long