Ajout du moteur de recherche dans le header
This commit is contained in:
@@ -10,20 +10,20 @@ namespace Webzine.Repository.Contracts
|
|||||||
|
|
||||||
// void Delete(Titre titre);
|
// void Delete(Titre titre);
|
||||||
|
|
||||||
// Titre Find(int idTitre);
|
Titre? Find(int idTitre);
|
||||||
|
|
||||||
// IEnumerable<Titre> FindTitres(int offset, int limit);
|
// IEnumerable<Titre> FindTitres(int offset, int limit);
|
||||||
|
|
||||||
// IEnumerable<Titre> FindAll();
|
IEnumerable<Titre> FindAll();
|
||||||
|
|
||||||
// void IncrementNbLectures(Titre titre);
|
// void IncrementNbLectures(Titre titre);
|
||||||
|
|
||||||
// void IncrementNbLikes(Titre titre);
|
// void IncrementNbLikes(Titre titre);
|
||||||
|
|
||||||
// IEnumerable<Titre> Search(string mot);
|
IEnumerable<Titre> Search(string mot);
|
||||||
|
|
||||||
// IEnumerable<Titre> SearchByStyle(string libelle);
|
IEnumerable<Titre> SearchByStyle(string libelle);
|
||||||
|
|
||||||
// void Update(Titre titre);
|
// void Update(Titre titre);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,71 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Webzine.Entity;
|
||||||
|
using Webzine.Entity.Fixtures;
|
||||||
|
using Webzine.Repository.Contracts;
|
||||||
|
|
||||||
namespace Webzine.Repository;
|
namespace Webzine.Repository;
|
||||||
|
|
||||||
public class LocalEntityRepository
|
/// <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 ILogger<LocalEntityRepository> _logger;
|
||||||
|
private readonly List<Titre> _titres;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialise une nouvelle instance du <see cref="LocalEntityRepository"/> avec un service de journalisation injecté.
|
/// Initialise une nouvelle instance du <see cref="LocalEntityRepository"/> avec un service de journalisation injecte.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger">Service de journalisation injecté pour suivre les opérations du repository.</param>
|
/// <param name="logger">Service de journalisation injecte pour suivre les operations du repository.</param>
|
||||||
public LocalEntityRepository(ILogger<LocalEntityRepository> logger)
|
public LocalEntityRepository(ILogger<LocalEntityRepository> logger)
|
||||||
{
|
{
|
||||||
this._logger = logger;
|
_logger = logger;
|
||||||
this._logger.LogDebug(1, "NLog injected into LocalEntityRepository");
|
_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> FindAll()
|
||||||
|
{
|
||||||
|
return _titres;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Webzine.Entity\Webzine.Entity.csproj" />
|
<ProjectReference Include="..\Webzine.Entity\Webzine.Entity.csproj" />
|
||||||
|
<ProjectReference Include="..\Webzine.Repository.Contracts\Webzine.Repository.Contracts.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
63
Webzine.WebApplication/Controllers/RechercheController.cs
Normal file
63
Webzine.WebApplication/Controllers/RechercheController.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Webzine.Repository.Contracts;
|
||||||
|
using Webzine.WebApplication.ViewModels.Recherche;
|
||||||
|
using Webzine.WebApplication.ViewModels.Titre;
|
||||||
|
|
||||||
|
namespace Webzine.WebApplication.Controllers;
|
||||||
|
|
||||||
|
[Route("recherche")]
|
||||||
|
public class RechercheController : Controller
|
||||||
|
{
|
||||||
|
private readonly ILogger<RechercheController> _logger;
|
||||||
|
private readonly ITitreRepository _titreRepository;
|
||||||
|
|
||||||
|
public RechercheController(ILogger<RechercheController> logger, ITitreRepository titreRepository)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_titreRepository = titreRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("")]
|
||||||
|
public IActionResult Index(string mot)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Recherche artistes/titres pour le mot : {Mot}.", mot);
|
||||||
|
|
||||||
|
var titres = _titreRepository.Search(mot)
|
||||||
|
.Concat(_titreRepository.SearchByStyle(mot))
|
||||||
|
.DistinctBy(t => t.IdTitre)
|
||||||
|
.OrderBy(t => t.Libelle)
|
||||||
|
.Select(t => new TitreStyleItem
|
||||||
|
{
|
||||||
|
IdTitre = t.IdTitre,
|
||||||
|
Libelle = t.Libelle,
|
||||||
|
ArtisteNom = t.Artiste?.Nom,
|
||||||
|
UrlJaquette = t.UrlJaquette,
|
||||||
|
Duree = t.Duree
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var artistes = _titreRepository.FindAll()
|
||||||
|
.Select(t => t.Artiste)
|
||||||
|
.Where(a => a != null
|
||||||
|
&& !string.IsNullOrWhiteSpace(a.Nom)
|
||||||
|
&& !string.IsNullOrWhiteSpace(mot)
|
||||||
|
&& a.Nom.Contains(mot, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.DistinctBy(a => a!.IdArtiste)
|
||||||
|
.OrderBy(a => a!.Nom)
|
||||||
|
.Select(a => new RechercheArtisteItem
|
||||||
|
{
|
||||||
|
Nom = a!.Nom,
|
||||||
|
NombreDeTitres = a.Titres?.Count ?? 0
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var vm = new RechercheIndexViewModel
|
||||||
|
{
|
||||||
|
Mot = mot,
|
||||||
|
Artistes = artistes,
|
||||||
|
Titres = titres
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,56 +1,45 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Webzine.Entity;
|
using Webzine.Entity;
|
||||||
using Webzine.Entity.Fixtures;
|
using Webzine.Repository.Contracts;
|
||||||
using Webzine.WebApplication.ViewModels.Titre;
|
using Webzine.WebApplication.ViewModels.Titre;
|
||||||
|
|
||||||
namespace Webzine.WebApplication.Controllers;
|
namespace Webzine.WebApplication.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contrôleur responsable de la gestion des titres musicaux :
|
/// Controleur responsable de la gestion des titres musicaux :
|
||||||
/// affichage des détails, filtrage par style,
|
/// affichage des details, filtrage par style,
|
||||||
/// ajout de likes et commentaires.
|
/// ajout de likes, commentaires et recherche.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("titre")]
|
[Route("titre")]
|
||||||
public class TitreController : Controller
|
public class TitreController : Controller
|
||||||
{
|
{
|
||||||
private readonly ILogger<TitreController> _logger;
|
private readonly ILogger<TitreController> _logger;
|
||||||
private readonly List<Titre> _titres;
|
private readonly ITitreRepository _titreRepository;
|
||||||
private readonly List<Style> _styles;
|
|
||||||
private readonly List<Artiste> _artistes;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialise une nouvelle instance du <see cref="TitreController"/>.
|
/// Initialise une nouvelle instance du <see cref="TitreController"/>.
|
||||||
/// Les données sont générées dynamiquement via <see cref="DataFactory"/>.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger">Service de journalisation injecté.</param>
|
/// <param name="logger">Service de journalisation injecte.</param>
|
||||||
public TitreController(ILogger<TitreController> logger)
|
/// <param name="titreRepository">Repository des titres injecte.</param>
|
||||||
|
public TitreController(ILogger<TitreController> logger, ITitreRepository titreRepository)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_titreRepository = titreRepository;
|
||||||
|
|
||||||
_logger.LogInformation("Initialisation du contrôleur TitreController.");
|
_logger.LogInformation("Initialisation du controleur TitreController.");
|
||||||
|
|
||||||
var factory = new DataFactory();
|
|
||||||
|
|
||||||
_artistes = factory.GenerateArtists(10);
|
|
||||||
_styles = factory.GenerateStyles(10);
|
|
||||||
_titres = factory.GenerateTitres(30, _artistes, _styles);
|
|
||||||
|
|
||||||
factory.GenerateCommentaires(50, _titres);
|
|
||||||
|
|
||||||
_logger.LogInformation("Données fictives générées avec succès.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Affiche le détail d'un titre spécifique.
|
/// Affiche le detail d'un titre specifique.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">Identifiant du titre.</param>
|
/// <param name="id">Identifiant du titre.</param>
|
||||||
/// <returns>Vue des détails ou 404 si introuvable.</returns>
|
/// <returns>Vue des details ou 404 si introuvable.</returns>
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public IActionResult Details(int id)
|
public IActionResult Details(int id)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Demande d'affichage du détail pour le titre ID {Id}.", id);
|
_logger.LogInformation("Demande d'affichage du detail pour le titre ID {Id}.", id);
|
||||||
|
|
||||||
var titre = _titres.FirstOrDefault(t => t.IdTitre == id);
|
var titre = FindById(id);
|
||||||
|
|
||||||
if (titre == null)
|
if (titre == null)
|
||||||
{
|
{
|
||||||
@@ -83,53 +72,37 @@ public class TitreController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Affiche les titres correspondant à un style musical donné.
|
/// Affiche les titres correspondant a un style musical donne.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="style">Nom du style musical.</param>
|
/// <param name="style">Nom du style musical.</param>
|
||||||
/// <returns>Vue contenant la liste filtrée.</returns>
|
/// <returns>Vue contenant la liste filtree.</returns>
|
||||||
[HttpGet("style/{style}")]
|
[HttpGet("style/{style}")]
|
||||||
public IActionResult Style(string style)
|
public IActionResult Style(string style)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Recherche des titres pour le style : {Style}.", style);
|
_logger.LogInformation("Recherche des titres pour le style : {Style}.", style);
|
||||||
|
|
||||||
var titresFiltres = _titres
|
var titresFiltres = _titreRepository.SearchByStyle(style).ToList();
|
||||||
.Where(t => t.Styles.Any(s => s.Libelle.Equals(style)))
|
|
||||||
.OrderBy(t => t.Libelle)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (!titresFiltres.Any())
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Aucun titre trouvé pour le style : {Style}.", style);
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
var vm = new TitreStyle
|
var vm = new TitreStyle
|
||||||
{
|
{
|
||||||
StyleName = style,
|
StyleName = style,
|
||||||
Titres = titresFiltres.Select(t => new TitreStyleItem
|
Titres = titresFiltres.Select(MapTitreItem).ToList()
|
||||||
{
|
|
||||||
IdTitre = t.IdTitre,
|
|
||||||
Libelle = t.Libelle,
|
|
||||||
ArtisteNom = t.Artiste?.Nom,
|
|
||||||
UrlJaquette = t.UrlJaquette,
|
|
||||||
Duree = t.Duree
|
|
||||||
}).ToList()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return View(vm);
|
return View(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ajoute un like à un titre.
|
/// Ajoute un like a un titre.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">Modèle contenant l'identifiant du titre.</param>
|
/// <param name="model">Modele contenant l'identifiant du titre.</param>
|
||||||
/// <returns>Redirection vers la page détail.</returns>
|
/// <returns>Redirection vers la page detail.</returns>
|
||||||
[HttpPost("like")]
|
[HttpPost("like")]
|
||||||
public IActionResult Like(TitreLike model)
|
public IActionResult Like(TitreLike model)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Ajout d'un like pour le titre ID {Id}.", model.IdTitre);
|
_logger.LogInformation("Ajout d'un like pour le titre ID {Id}.", model.IdTitre);
|
||||||
|
|
||||||
var titre = _titres.FirstOrDefault(t => t.IdTitre == model.IdTitre);
|
var titre = FindById(model.IdTitre);
|
||||||
|
|
||||||
if (titre == null)
|
if (titre == null)
|
||||||
{
|
{
|
||||||
@@ -143,20 +116,20 @@ public class TitreController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ajoute un commentaire à un titre.
|
/// Ajoute un commentaire a un titre.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">Données du commentaire.</param>
|
/// <param name="model">Donnees du commentaire.</param>
|
||||||
/// <returns>Redirection vers la page détail.</returns>
|
/// <returns>Redirection vers la page detail.</returns>
|
||||||
[HttpPost("comment")]
|
[HttpPost("comment")]
|
||||||
public IActionResult Comment(TitreComment model)
|
public IActionResult Comment(TitreComment model)
|
||||||
{
|
{
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Échec de validation du modèle de commentaire pour le titre ID {Id}.", model.IdTitre);
|
_logger.LogWarning("Echec de validation du modele de commentaire pour le titre ID {Id}.", model.IdTitre);
|
||||||
return RedirectToAction("Details", new { id = model.IdTitre });
|
return RedirectToAction("Details", new { id = model.IdTitre });
|
||||||
}
|
}
|
||||||
|
|
||||||
var titre = _titres.FirstOrDefault(t => t.IdTitre == model.IdTitre);
|
var titre = FindById(model.IdTitre);
|
||||||
|
|
||||||
if (titre == null)
|
if (titre == null)
|
||||||
{
|
{
|
||||||
@@ -174,8 +147,25 @@ public class TitreController : Controller
|
|||||||
|
|
||||||
titre.Commentaires.Add(commentaire);
|
titre.Commentaires.Add(commentaire);
|
||||||
|
|
||||||
_logger.LogInformation("Commentaire ajouté avec succès au titre ID {Id}.", model.IdTitre);
|
_logger.LogInformation("Commentaire ajoute avec succes au titre ID {Id}.", model.IdTitre);
|
||||||
|
|
||||||
return RedirectToAction("Details", new { id = model.IdTitre });
|
return RedirectToAction("Details", new { id = model.IdTitre });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private Titre? FindById(int id)
|
||||||
|
{
|
||||||
|
return _titreRepository.Find(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TitreStyleItem MapTitreItem(Titre titre)
|
||||||
|
{
|
||||||
|
return new TitreStyleItem
|
||||||
|
{
|
||||||
|
IdTitre = titre.IdTitre,
|
||||||
|
Libelle = titre.Libelle,
|
||||||
|
ArtisteNom = titre.Artiste?.Nom,
|
||||||
|
UrlJaquette = titre.UrlJaquette,
|
||||||
|
Duree = titre.Duree
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Web;
|
using NLog.Web;
|
||||||
|
using Webzine.Repository;
|
||||||
|
using Webzine.Repository.Contracts;
|
||||||
|
|
||||||
// Initiation du logger NLog pour la classe courante afin de pouvoir l'utiliser pour logger des messages d'information, d'erreur, etc avant la construction de l'application.
|
// Initiation du logger NLog pour la classe courante afin de pouvoir l'utiliser pour logger des messages d'information, d'erreur, etc avant la construction de l'application.
|
||||||
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||||
@@ -9,28 +11,29 @@ try
|
|||||||
{
|
{
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Ajoute les services nécessaires pour permettre l'utilisation des
|
// Ajoute les services necessaires pour permettre l'utilisation des
|
||||||
// controllers avec des vues.
|
// controllers avec des vues.
|
||||||
builder.Services.AddControllersWithViews()
|
builder.Services.AddControllersWithViews()
|
||||||
// Ajoute la compilation des vues lors de l'exécution de l'application.
|
// Ajoute la compilation des vues lors de l'execution de l'application.
|
||||||
// Cela nous évite de recompiler l'application à chaque modification de vue.
|
// Cela nous evite de recompiler l'application a chaque modification de vue.
|
||||||
// Nécessite le package Nuget Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.
|
// Necessite le package Nuget Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.
|
||||||
.AddRazorRuntimeCompilation();
|
.AddRazorRuntimeCompilation();
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<ITitreRepository, LocalEntityRepository>();
|
||||||
|
|
||||||
// NLog: Setup NLog for Dependency injection
|
// NLog: Setup NLog for Dependency injection
|
||||||
builder.Logging.ClearProviders();
|
builder.Logging.ClearProviders();
|
||||||
builder.Host.UseNLog();
|
builder.Host.UseNLog();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Active la possibilité de servir des fichiers statiques présents dans
|
// Active la possibilite de servir des fichiers statiques presents dans
|
||||||
// le dossier wwwroot.
|
// le dossier wwwroot.
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
// Active le middleware permettant le routage des requétes entrantes.
|
// Active le middleware permettant le routage des requetes entrantes.
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
|
||||||
// Ajoute une route pour les zones (Areas) comme Admin
|
// Ajoute une route pour les zones (Areas) comme Admin
|
||||||
app.MapControllerRoute(
|
app.MapControllerRoute(
|
||||||
name: "areas",
|
name: "areas",
|
||||||
@@ -46,7 +49,7 @@ try
|
|||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
// NLog: attrape les exceptions non gérées et les logge.
|
// NLog: attrape les exceptions non gerees et les logge.
|
||||||
logger.Error(exception, "Stopped program because of exception");
|
logger.Error(exception, "Stopped program because of exception");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@@ -54,4 +57,4 @@ finally
|
|||||||
{
|
{
|
||||||
// Assure que NLog flush tous les messages de log avant de fermer l'application.
|
// Assure que NLog flush tous les messages de log avant de fermer l'application.
|
||||||
NLog.LogManager.Shutdown();
|
NLog.LogManager.Shutdown();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace Webzine.WebApplication.ViewModels.Recherche;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ViewModel pour afficher un artiste dans les resultats de recherche.
|
||||||
|
/// </summary>
|
||||||
|
public class RechercheArtisteItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Nom de l'artiste.
|
||||||
|
/// </summary>
|
||||||
|
public string? Nom { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Nombre de titres associes a l'artiste.
|
||||||
|
/// </summary>
|
||||||
|
public int NombreDeTitres { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using Webzine.WebApplication.ViewModels.Titre;
|
||||||
|
|
||||||
|
namespace Webzine.WebApplication.ViewModels.Recherche;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ViewModel pour afficher les resultats de recherche d'artistes et de titres.
|
||||||
|
/// </summary>
|
||||||
|
public class RechercheIndexViewModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Mot saisi dans le formulaire.
|
||||||
|
/// </summary>
|
||||||
|
public string? Mot { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Artistes trouves.
|
||||||
|
/// </summary>
|
||||||
|
public List<RechercheArtisteItem> Artistes { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Titres trouves.
|
||||||
|
/// </summary>
|
||||||
|
public List<TitreStyleItem> Titres { get; set; } = new();
|
||||||
|
}
|
||||||
85
Webzine.WebApplication/Views/Recherche/Index.cshtml
Normal file
85
Webzine.WebApplication/Views/Recherche/Index.cshtml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
@model Webzine.WebApplication.ViewModels.Recherche.RechercheIndexViewModel
|
||||||
|
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Recherche";
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<h1 class="mb-4">Resultats pour "@Model.Mot"</h1>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
@if (string.IsNullOrWhiteSpace(Model.Mot))
|
||||||
|
{
|
||||||
|
<div class="alert alert-info">
|
||||||
|
Saisissez un mot-cle pour lancer une recherche.
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (!Model.Artistes.Any() && !Model.Titres.Any())
|
||||||
|
{
|
||||||
|
<div class="alert alert-info">
|
||||||
|
Aucun artiste ni titre ne correspond a votre recherche.
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@if (Model.Artistes.Any())
|
||||||
|
{
|
||||||
|
<h2 class="h4 mt-4">Artistes</h2>
|
||||||
|
|
||||||
|
@foreach (var artiste in Model.Artistes)
|
||||||
|
{
|
||||||
|
<div class="my-3">
|
||||||
|
<a asp-controller="Artiste"
|
||||||
|
asp-action="Index"
|
||||||
|
asp-route-nom="@artiste.Nom">
|
||||||
|
@artiste.Nom
|
||||||
|
</a>
|
||||||
|
<span class="text-muted">(@artiste.NombreDeTitres titre(s))</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (Model.Titres.Any())
|
||||||
|
{
|
||||||
|
<h2 class="h4 mt-4">Titres</h2>
|
||||||
|
|
||||||
|
@foreach (var titre in Model.Titres)
|
||||||
|
{
|
||||||
|
<div class="d-flex align-items-start my-3">
|
||||||
|
<a asp-controller="Titre"
|
||||||
|
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" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="justify-content-center d-flex flex-column">
|
||||||
|
<div>
|
||||||
|
<a asp-controller="Artiste"
|
||||||
|
asp-action="Index"
|
||||||
|
asp-route-nom="@titre.ArtisteNom">
|
||||||
|
@titre.ArtisteNom
|
||||||
|
</a>
|
||||||
|
-
|
||||||
|
<a asp-controller="Titre"
|
||||||
|
asp-action="Details"
|
||||||
|
asp-route-id="@titre.IdTitre">
|
||||||
|
@titre.Libelle
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Duree : @TimeSpan.FromSeconds(titre.Duree).ToString(@"mm\:ss")
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
*@
|
*@
|
||||||
@{
|
@{
|
||||||
}
|
}
|
||||||
<div class="text-bg-light my-2 pb-0">
|
<div class="site-footer text-bg-light mt-auto">
|
||||||
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4">
|
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3">
|
||||||
<div class="col-md-4 d-flex align-items-center">
|
<div class="col-md-4 d-flex align-items-center">
|
||||||
|
|
||||||
<span class="mb-3 mb-md-0 ms-5 text-body-secondary">© ASP .NET Core - DIIAGE 2025 - 2026</span>
|
<span class="mb-3 mb-md-0 ms-5 text-body-secondary">© ASP .NET Core - DIIAGE 2025 - 2026</span>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -62,10 +62,13 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!-- Barre de recherche -->
|
<!-- Barre de recherche -->
|
||||||
<form class="d-flex">
|
<form class="d-flex" asp-controller="Recherche" asp-action="Index" method="post">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="form-outline">
|
<div class="form-outline">
|
||||||
<input class="form-control me-2" type="search" placeholder="Trouver un artiste / titre">
|
<input class="form-control me-2"
|
||||||
|
type="search"
|
||||||
|
name="mot"
|
||||||
|
placeholder="Trouver un artiste, un titre ou un style">
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary" type="submit">
|
<button class="btn btn-primary" type="submit">
|
||||||
<i class="fa-solid fa-magnifying-glass"></i>
|
<i class="fa-solid fa-magnifying-glass"></i>
|
||||||
@@ -75,4 +78,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -15,18 +15,20 @@
|
|||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="pb-0 mb-0">
|
<div class="site-shell">
|
||||||
<partial name="_Header"/>
|
<partial name="_Header"/>
|
||||||
<div class="row mt-5">
|
<div class="container-fluid flex-grow-1 py-4">
|
||||||
<main class="col mx-3">
|
<div class="row g-0">
|
||||||
@RenderBody()
|
<main class="col mx-3">
|
||||||
</main>
|
@RenderBody()
|
||||||
@if(ViewContext.RouteData.Values["area"]?.ToString() != "Administration")
|
</main>
|
||||||
{
|
@if(ViewContext.RouteData.Values["area"]?.ToString() != "Administration")
|
||||||
<partial name="_Sidebar" />
|
{
|
||||||
}
|
<partial name="_Sidebar" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<partial name="_Footer" />
|
<partial name="_Footer" />
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user