Transforme la bibliographie en écran de travail D1 à D5

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
LIMONIER Mathieu
2026-08-20 13:42:46 +02:00
co-authored by Copilot
parent ddc60898da
commit 359f4f59c6
13 changed files with 1044 additions and 20 deletions
@@ -1,6 +1,7 @@
using MaBibli.Api.Data;
using MaBibli.Api.Services.Isbn;
using MaBibli.Shared.Dtos;
using MaBibli.Shared.Entites;
using MaBibli.Shared.Textes;
using Microsoft.EntityFrameworkCore;
@@ -13,6 +14,10 @@ public interface IServiceBibliographie
/// l'appelant souhaite déjà. <c>null</c> si l'auteur n'existe pas.
/// </summary>
Task<BibliographieDto?> ObtenirAsync(int auteurId, string? utilisateur, CancellationToken ct = default);
Task<bool> MasquerAsync(int auteurId, string titre, string? utilisateur, CancellationToken ct = default);
Task<bool> DemasquerAsync(int auteurId, string titre, string? utilisateur, CancellationToken ct = default);
}
/// <summary>
@@ -73,9 +78,10 @@ public sealed class ServiceBibliographie(
}
var souhaits = await SouhaitsAsync(utilisateur, ct);
var masquees = await MasqueesAsync(auteurId, utilisateur, ct);
var oeuvres = Regrouper(resultat)
.Select(o => Confronter(o, parTitre, parIsbn, souhaits))
.Select(o => Confronter(o, parTitre, parIsbn, souhaits, masquees))
.OrderByDescending(o => AnneeTriable(o.Annee))
.ThenBy(o => o.Titre, StringComparer.CurrentCultureIgnoreCase)
.ToList();
@@ -95,6 +101,58 @@ public sealed class ServiceBibliographie(
};
}
public async Task<bool> MasquerAsync(
int auteurId, string titre, string? utilisateur, CancellationToken ct = default)
{
if (utilisateur is null)
{
return false;
}
var cle = CleOeuvre.Cle(titre);
if (cle.Length == 0)
{
return false;
}
var existe = await db.BibliographiesMasquees.AnyAsync(
m => m.AuteurId == auteurId && m.Utilisateur == utilisateur && m.TitreNormalise == cle, ct);
if (existe)
{
return true;
}
db.BibliographiesMasquees.Add(new BibliographieMasquee
{
AuteurId = auteurId,
Utilisateur = utilisateur,
TitreNormalise = cle,
});
await db.SaveChangesAsync(ct);
return true;
}
public async Task<bool> DemasquerAsync(
int auteurId, string titre, string? utilisateur, CancellationToken ct = default)
{
if (utilisateur is null)
{
return false;
}
var cle = CleOeuvre.Cle(titre);
var ligne = await db.BibliographiesMasquees.FirstOrDefaultAsync(
m => m.AuteurId == auteurId && m.Utilisateur == utilisateur && m.TitreNormalise == cle, ct);
if (ligne is null)
{
return false;
}
db.BibliographiesMasquees.Remove(ligne);
await db.SaveChangesAsync(ct);
return true;
}
/// <summary>Clés d'œuvre déjà souhaitées par l'appelant, avec l'identifiant de l'envie.</summary>
private async Task<Dictionary<string, int>> SouhaitsAsync(string? utilisateur, CancellationToken ct)
{
@@ -118,6 +176,22 @@ public sealed class ServiceBibliographie(
return index;
}
private async Task<HashSet<string>> MasqueesAsync(
int auteurId, string? utilisateur, CancellationToken ct)
{
if (utilisateur is null)
{
return [];
}
var cles = await db.BibliographiesMasquees
.AsNoTracking()
.Where(m => m.AuteurId == auteurId && m.Utilisateur == utilisateur)
.Select(m => m.TitreNormalise)
.ToListAsync(ct);
return cles.ToHashSet(StringComparer.Ordinal);
}
/// <summary>
/// Réunit les rééditions sous une seule œuvre.
/// </summary>
@@ -158,7 +232,8 @@ public sealed class ServiceBibliographie(
OeuvreBibliographie oeuvre,
IReadOnlyDictionary<string, int> parTitre,
IReadOnlyDictionary<string, int> parIsbn,
IReadOnlyDictionary<string, int> souhaits)
IReadOnlyDictionary<string, int> souhaits,
IReadOnlySet<string> masquees)
{
var cle = CleOeuvre.Cle(oeuvre.Titre);
@@ -179,6 +254,7 @@ public sealed class ServiceBibliographie(
LivreId = livreId,
Souhaite = souhaitId is not null,
SouhaitId = souhaitId,
Masquee = masquees.Contains(cle),
};
}