Format disait physique ou numérique, jamais roman ou BD. Trois valeurs seulement : une valeur s'ajoute sans migration, la renommer une fois posée sur des centaines de fiches, non. Le défaut est « non précisé », pas « roman » : les fiches existantes n'ont pas été saisies avec cette question en tête, et un AddColumn suffit justement parce que la valeur par défaut ne prétend rien. L'interface n'affiche donc que ce qui a été choisi, comme pour le format. Filtre ajouté aux DEUX implémentations, serveur et hors-ligne, avec quatre jeux de critères de plus dans le test qui les confronte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
82 lines
3.2 KiB
C#
82 lines
3.2 KiB
C#
using System.Text.Json.Serialization;
|
|
using MaBibli.Shared.Entites;
|
|
|
|
namespace MaBibli.Shared.Dtos;
|
|
|
|
/// <summary>
|
|
/// Charge utile de création et de modification d'un livre.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <see cref="Livre.AjoutePar"/> n'y figure pas volontairement : il est déterminé par le serveur
|
|
/// à partir de l'utilisateur authentifié, jamais par le client.
|
|
/// </remarks>
|
|
public record EnregistrementLivre
|
|
{
|
|
/// <summary>Séparateur des auteurs dans la forme texte d'un champ de saisie.</summary>
|
|
/// <remarks>
|
|
/// Le point-virgule, et non la virgule : celle-ci est déjà prise par la forme
|
|
/// bibliographique « Zola, Émile », qu'on doit pouvoir taper telle quelle.
|
|
/// </remarks>
|
|
public const char SeparateurAuteurs = ';';
|
|
|
|
/// <summary>Facultatif : certains livres n'ont pas d'ISBN. Normalisé par le serveur.</summary>
|
|
public string? Isbn { get; set; }
|
|
|
|
public string Titre { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Noms des auteurs, dans l'ordre de la couverture. Le serveur les rattache aux fiches
|
|
/// existantes quand c'est sûr, et en crée sinon.
|
|
/// </summary>
|
|
public List<string> Auteurs { get; set; } = [];
|
|
|
|
public string? Editeur { get; set; }
|
|
|
|
public Format Format { get; set; }
|
|
|
|
/// <summary>Roman, bande dessinée… Facultatif : « non précisé » est une réponse valable.</summary>
|
|
public TypeDocument TypeDocument { get; set; }
|
|
|
|
/// <summary>
|
|
/// Statut de lecture <b>de l'appelant</b>. <c>null</c> = non commencé, et aucune ligne n'est
|
|
/// alors écrite en base.
|
|
/// </summary>
|
|
public Statut? Statut { get; set; }
|
|
|
|
public string? CoverUrl { get; set; }
|
|
|
|
/// <summary>
|
|
/// Vue « une seule ligne » de <see cref="Auteurs"/>, pour les champs de saisie simples.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Non sérialisée : <see cref="Auteurs"/> est la forme de référence sur le fil. Cette
|
|
/// propriété existe pour que l'interface puisse lier un <c><input></c> unique sans
|
|
/// avoir à gérer une liste dynamique — un foyer saisit un auteur dans l'immense majorité
|
|
/// des cas, et les rares livres à quatre auteurs se tapent avec des « ; ».
|
|
/// </remarks>
|
|
[JsonIgnore]
|
|
public string? Auteur
|
|
{
|
|
get => Auteurs.Count == 0 ? null : string.Join($"{SeparateurAuteurs} ", Auteurs);
|
|
set => Auteurs = Decouper(value);
|
|
}
|
|
|
|
/// <summary>Découpe une saisie texte en noms d'auteurs, en écartant les entrées vides.</summary>
|
|
public static List<string> Decouper(string? saisie) =>
|
|
string.IsNullOrWhiteSpace(saisie)
|
|
? []
|
|
: saisie.Split(SeparateurAuteurs, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
|
.ToList();
|
|
}
|
|
|
|
/// <summary>Charge utile du changement de statut de lecture — l'action la plus fréquente.</summary>
|
|
/// <remarks>
|
|
/// Le statut posé est toujours celui de l'appelant : il n'y a pas de champ « utilisateur »,
|
|
/// et il ne doit jamais y en avoir. Personne ne coche « lu » à la place d'un autre.
|
|
/// </remarks>
|
|
public record ChangementStatut
|
|
{
|
|
/// <summary><c>null</c> retire le statut : le livre redevient « non commencé » pour l'appelant.</summary>
|
|
public Statut? Statut { get; set; }
|
|
}
|