Gestion de bibliothèque personnelle auto-hébergée : catalogue, prêts, scan de code-barres, consultation hors-ligne. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
269 lines
10 KiB
C#
269 lines
10 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace MaBibli.Shared.Dtos;
|
|
|
|
/// <summary>
|
|
/// Une envie telle qu'exposée par l'API.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Il n'y a <b>aucun champ « utilisateur »</b>, et il ne doit jamais y en avoir : l'API ne rend
|
|
/// que les envies de l'appelant, qu'elle identifie par les en-têtes SSOwat. Exposer le
|
|
/// propriétaire laisserait croire qu'on peut demander celles d'un autre.
|
|
/// </remarks>
|
|
public record SouhaitDto
|
|
{
|
|
public required int Id { get; init; }
|
|
|
|
public required string Titre { get; init; }
|
|
|
|
public string? Auteur { get; init; }
|
|
|
|
public string? Editeur { get; init; }
|
|
|
|
public string? Annee { get; init; }
|
|
|
|
public string? Isbn { get; init; }
|
|
|
|
public string? CoverUrl { get; init; }
|
|
|
|
public string? Note { get; init; }
|
|
|
|
public required DateTime DateAjout { get; init; }
|
|
|
|
/// <summary>
|
|
/// Vrai si un livre du catalogue correspond à cette envie.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <b>C'est un signalement, jamais une suppression.</b> Le catalogue est commun, la liste
|
|
/// d'envies personnelle : retirer l'envie de quelqu'un d'autre modifierait sa liste en
|
|
/// silence et lui ferait perdre sa note (« demandé à Noël »). Le rapprochement est en outre
|
|
/// faillible (voir <c>CleOeuvre</c>) — un signalement erroné s'ignore d'un coup d'œil, une
|
|
/// suppression erronée ne se rattrape pas.
|
|
/// </remarks>
|
|
public bool Possede { get; init; }
|
|
|
|
/// <summary>Le livre du catalogue en cause, s'il y en a un : de quoi ouvrir sa fiche.</summary>
|
|
public int? LivreId { get; init; }
|
|
}
|
|
|
|
/// <summary>Charge utile d'ajout d'une envie.</summary>
|
|
/// <remarks>
|
|
/// Comme <see cref="EnregistrementLivre"/>, elle ne porte pas d'identité : le propriétaire est
|
|
/// déterminé par le serveur.
|
|
/// </remarks>
|
|
public record EnregistrementSouhait
|
|
{
|
|
public string Titre { get; set; } = string.Empty;
|
|
|
|
public string? Auteur { get; set; }
|
|
|
|
public string? Editeur { get; set; }
|
|
|
|
public string? Annee { get; set; }
|
|
|
|
public string? Isbn { get; set; }
|
|
|
|
public string? CoverUrl { get; set; }
|
|
|
|
public string? Note { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Une envie de revue — ou de numéro précis — telle qu'exposée par l'API.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Comme <see cref="SouhaitDto"/>, <b>aucun champ « utilisateur »</b> : l'API ne rend que les
|
|
/// envies de l'appelant.
|
|
/// <para>
|
|
/// Il n'y a volontairement <b>ni « Possede » ni « RevueId »</b>, contrairement aux envies de
|
|
/// livres : le rapprochement avec les revues possédées supposerait de décider ce que vaut
|
|
/// « j'ai la revue mais pas ce numéro », et un signalement faux sur une liste d'envies est
|
|
/// exactement ce qu'on cherche à éviter. Rien n'empêchera de l'ajouter le jour où le besoin
|
|
/// sera constaté.
|
|
/// </para>
|
|
/// </remarks>
|
|
public record RevueSouhaiteeDto
|
|
{
|
|
public required int Id { get; init; }
|
|
|
|
public required string Titre { get; init; }
|
|
|
|
/// <summary><c>null</c> = la revue entière, pas un numéro particulier.</summary>
|
|
public string? Numero { get; init; }
|
|
|
|
/// <summary>ISSN sous sa forme à tiret, la seule rangée en base.</summary>
|
|
public string? Issn { get; init; }
|
|
|
|
public string? Note { get; init; }
|
|
|
|
public required DateTime DateAjout { get; init; }
|
|
|
|
/// <summary>Titre suivi de son numéro, tel qu'on l'épelle à un kiosquier.</summary>
|
|
[JsonIgnore]
|
|
public string TitreComplet =>
|
|
string.IsNullOrWhiteSpace(Numero) ? Titre : $"{Titre} n° {Numero}";
|
|
}
|
|
|
|
/// <summary>Charge utile d'ajout ou de modification d'une envie de revue.</summary>
|
|
/// <remarks>Sans identité : le propriétaire est déterminé par le serveur.</remarks>
|
|
public record EnregistrementRevueSouhaitee
|
|
{
|
|
public string Titre { get; set; } = string.Empty;
|
|
|
|
public string? Numero { get; set; }
|
|
|
|
public string? Issn { get; set; }
|
|
|
|
public string? Note { get; set; }
|
|
}
|
|
|
|
/// <summary>Charge utile du masquage personnel d'une œuvre bibliographique.</summary>
|
|
public record MasquageBibliographie
|
|
{
|
|
public string Titre { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>Formats d'export de la liste d'envies.</summary>
|
|
/// <remarks>
|
|
/// Les deux usages décrits dans CLAUDE.md ne demandent pas la même chose : « l'emporter en
|
|
/// librairie » veut un texte qui se lit tel quel sur un téléphone, « la partager avant un
|
|
/// anniversaire » finit souvent dans un tableur pour se répartir les achats. Ni l'un ni l'autre
|
|
/// n'exige de dépendance : ce sont deux fichiers texte produits par du <c>string</c>.
|
|
/// </remarks>
|
|
public enum FormatExportSouhaits
|
|
{
|
|
/// <summary>Liste lisible telle quelle, groupée par auteur.</summary>
|
|
Texte = 0,
|
|
|
|
/// <summary>Tableau ouvrable dans un tableur.</summary>
|
|
Csv = 1,
|
|
}
|
|
|
|
/// <summary>Une œuvre de la bibliographie d'un auteur, confrontée à ce que l'on possède déjà.</summary>
|
|
public record OeuvreBibliographie
|
|
{
|
|
public required string Titre { get; init; }
|
|
|
|
public string? Annee { get; init; }
|
|
|
|
/// <summary>Année la plus récente des éditions BnF réunies sous cette œuvre.</summary>
|
|
/// <remarks>
|
|
/// L'année affichée reste celle de l'édition la plus ancienne, qui représente l'œuvre.
|
|
/// Cette seconde valeur sert uniquement à rechercher les nouveautés.
|
|
/// </remarks>
|
|
public int? AnneeDerniereEdition { get; init; }
|
|
|
|
public string? Editeur { get; init; }
|
|
|
|
/// <summary>ISBN d'une des éditions relevées, quand la notice en portait un.</summary>
|
|
public string? Isbn { get; init; }
|
|
|
|
/// <summary>
|
|
/// Nombre de notices BnF réunies sous cette œuvre — c'est-à-dire le nombre de rééditions
|
|
/// relevées. Sert à repérer les œuvres majeures d'un auteur très réédité.
|
|
/// </summary>
|
|
public int NombreEditions { get; init; }
|
|
|
|
/// <summary>
|
|
/// Vrai si un livre du catalogue porte le même titre d'œuvre.
|
|
/// <b>Rapprochement par titre, donc faillible</b> — voir <c>CleOeuvre</c>.
|
|
/// </summary>
|
|
public bool Possede { get; init; }
|
|
|
|
/// <summary>Le livre possédé, s'il y en a un : de quoi ouvrir sa fiche.</summary>
|
|
public int? LivreId { get; init; }
|
|
|
|
/// <summary>Vrai si l'appelant a déjà cette œuvre dans sa liste d'envies.</summary>
|
|
public bool Souhaite { get; init; }
|
|
|
|
public int? SouhaitId { get; init; }
|
|
|
|
/// <summary>Vrai si l'appelant a explicitement masqué cette œuvre.</summary>
|
|
public bool Masquee { get; init; }
|
|
|
|
/// <summary>Ni possédé, ni déjà souhaité : ce qui reste à découvrir.</summary>
|
|
[JsonIgnore]
|
|
public bool ADecouvrir => !Possede && !Souhaite;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ce qu'il est advenu de l'interrogation de la BnF.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// ⚠️ <b>Une source muette n'est pas une bibliographie vide</b>, et la différence n'est pas
|
|
/// cosmétique : sans cet état, un délai dépassé produisait une liste vide, que l'écran
|
|
/// commentait d'un rassurant « la BnF ne connaît aucun livre de cet auteur ». On affirmait donc
|
|
/// une chose qu'on n'avait pas pu vérifier. C'est ce que cet énuméré rend impossible.
|
|
/// <para>
|
|
/// Le motif est distingué parce qu'il ne demande pas la même chose à l'utilisateur : un délai
|
|
/// dépassé se retente, une réponse illisible non.
|
|
/// </para>
|
|
/// </remarks>
|
|
public enum EtatSourceBibliographie
|
|
{
|
|
/// <summary>La BnF a répondu. La liste rendue est ce qu'elle sait, y compris si elle est vide.</summary>
|
|
Ok = 0,
|
|
|
|
/// <summary>La BnF n'a pas répondu à temps. Cas le plus fréquent, et le plus souvent passager.</summary>
|
|
DelaiDepasse = 1,
|
|
|
|
/// <summary>La BnF n'a pas pu être jointe, ou a répondu par une erreur.</summary>
|
|
Injoignable = 2,
|
|
|
|
/// <summary>La BnF a répondu, mais sa réponse n'était pas exploitable.</summary>
|
|
ReponseIllisible = 3,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bibliographie d'un auteur du catalogue, telle que la BnF la connaît.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Les compteurs ne sont pas décoratifs : ils disent à l'utilisateur ce qu'il regarde. Sur un
|
|
/// auteur très réédité (Émile Zola : 2692 notices), on ne montre qu'un <b>extrait classé par
|
|
/// pertinence</b>, et le taire ferait passer une liste partielle pour une bibliographie complète.
|
|
/// </remarks>
|
|
public record BibliographieDto
|
|
{
|
|
public required AuteurDto Auteur { get; init; }
|
|
|
|
public IReadOnlyList<OeuvreBibliographie> Oeuvres { get; init; } = [];
|
|
|
|
/// <summary>Nombre total de notices que la BnF déclare pour cet auteur.</summary>
|
|
public int NoticesAnnoncees { get; init; }
|
|
|
|
/// <summary>Nombre de notices réellement lues (plafonné).</summary>
|
|
public int NoticesLues { get; init; }
|
|
|
|
/// <summary>Notices écartées parce qu'aucun de leurs auteurs n'est celui demandé.</summary>
|
|
public int NoticesEcartees { get; init; }
|
|
|
|
/// <summary>Vrai si la BnF en annonce plus qu'on n'en a lu : la liste est un extrait.</summary>
|
|
public bool Tronquee => NoticesAnnoncees > NoticesLues;
|
|
|
|
/// <summary>Message à afficher quand la source n'a pas pu être interrogée normalement.</summary>
|
|
public string? Avertissement { get; init; }
|
|
|
|
/// <summary>
|
|
/// Ce qu'il est advenu de l'interrogation. <see cref="EtatSourceBibliographie.Ok"/> ne veut
|
|
/// pas dire « des résultats », mais « une réponse ».
|
|
/// </summary>
|
|
public EtatSourceBibliographie Etat { get; init; }
|
|
|
|
/// <summary>Vrai quand la liste est limitée aux œuvres postérieures au seuil possédé.</summary>
|
|
public bool EstNouveautes { get; init; }
|
|
|
|
/// <summary>Année de publication la plus récente retrouvée pour un livre possédé.</summary>
|
|
public int? AnneeSeuilNouveautes { get; init; }
|
|
|
|
/// <summary>Vrai quand aucun ISBN ou titre possédé n'a permis de dater le seuil.</summary>
|
|
public bool SeuilNouveautesInconnu { get; init; }
|
|
|
|
/// <summary>
|
|
/// Vrai quand la BnF n'a pas répondu : la liste vide ne prouve alors <b>rien</b>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// C'est ce que l'interface doit consulter avant d'expliquer une absence de résultats.
|
|
/// </remarks>
|
|
public bool SourceMuette => Etat != EtatSourceBibliographie.Ok;
|
|
}
|