Ajoute les notices sources et le renommage fusionné des auteurs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
LIMONIER Mathieu
2026-08-20 14:27:42 +02:00
co-authored by Copilot
parent 6b8f08ef26
commit e28d5bce32
24 changed files with 935 additions and 3 deletions
+1
View File
@@ -431,6 +431,7 @@
Auteur = candidat.Auteur,
Editeur = candidat.Editeur,
CoverUrl = candidat.CoverUrl,
UrlNotice = candidat.UrlNotice,
Format = Format.Physique,
Statut = Statut.ALire,
};
+95
View File
@@ -79,15 +79,61 @@ else
tout ce qu'il a ecrit et marquer ce qui manque. *@
<a class="bouton bouton-compact bouton-discret"
href="@($"auteurs/{auteur.Id}/bibliographie")">Bibliographie</a>
@if (_auteurRenomme == auteur.Id)
{
<input class="champ-texte champ-auteur-renomme" @bind="_nomRenomme" />
<button type="button" class="bouton bouton-compact bouton-principal"
disabled="@_renommageEnCours" @onclick="RenommerAsync">
Enregistrer
</button>
<button type="button" class="bouton bouton-compact bouton-discret"
disabled="@_renommageEnCours" @onclick="AnnulerRenommage">
Annuler
</button>
}
else
{
<button type="button" class="bouton bouton-compact bouton-discret"
disabled="@(_enCours || !Reseau.EnLigne)"
title="@MotifBlocage"
@onclick="() => CommencerRenommage(auteur)">
Renommer
</button>
}
</li>
}
</ul>
}
@if (_collisionRenommage is not null)
{
<section class="message-avertissement" role="alert">
<p>
Un auteur existe déjà sous le nom « @_collisionRenommage.Nom ».
Les livres seront regroupés sous cette fiche.
Confirmer la fusion ?
</p>
<div class="actions-formulaire">
<button type="button" class="bouton bouton-principal"
disabled="@_renommageEnCours" @onclick="ConfirmerFusionAsync">
Oui, fusionner
</button>
<button type="button" class="bouton bouton-discret"
disabled="@_renommageEnCours" @onclick="AnnulerRenommage">
Annuler
</button>
</div>
</section>
}
@code {
private IReadOnlyList<AuteurDto>? _auteurs;
private IReadOnlyList<SuggestionRapprochement>? _suggestions;
private bool _enCours;
private bool _renommageEnCours;
private int? _auteurRenomme;
private string _nomRenomme = string.Empty;
private AuteurDto? _collisionRenommage;
private string? _erreur;
protected override void OnInitialized() => Reseau.Change += SurChangementReseau;
@@ -128,6 +174,55 @@ else
private Task RefuserAsync(SuggestionRapprochement suggestion) =>
DeciderAsync(() => Api.RefuserRapprochementAsync(suggestion.Source.Id, suggestion.Cible.Id));
private void CommencerRenommage(AuteurDto auteur)
{
_auteurRenomme = auteur.Id;
_nomRenomme = auteur.Nom;
_collisionRenommage = null;
_erreur = null;
}
private void AnnulerRenommage()
{
_auteurRenomme = null;
_collisionRenommage = null;
_nomRenomme = string.Empty;
}
private Task RenommerAsync() => EnvoyerRenommageAsync(false);
private Task ConfirmerFusionAsync() => EnvoyerRenommageAsync(true);
private async Task EnvoyerRenommageAsync(bool confirmerFusion)
{
if (_auteurRenomme is null || string.IsNullOrWhiteSpace(_nomRenomme))
{
_erreur = "Le nom de l'auteur est obligatoire.";
return;
}
_renommageEnCours = true;
_erreur = null;
var resultat = await Api.RenommerAuteurAsync(
_auteurRenomme.Value, _nomRenomme, confirmerFusion);
_renommageEnCours = false;
if (resultat is null)
{
_erreur = "Le renommage n'a pas pu être enregistré.";
return;
}
if (resultat.Collision is not null)
{
_collisionRenommage = resultat.Collision;
return;
}
AnnulerRenommage();
await ChargerAsync();
}
private async Task DeciderAsync(Func<Task<string?>> action)
{
_enCours = true;
+6
View File
@@ -149,6 +149,11 @@ else
{
<div><dt>Type</dt><dd>@Libelles.TypeDocument(_livre.TypeDocument)</dd></div>
}
@if (!string.IsNullOrWhiteSpace(_livre.UrlNotice))
{
<div><dt>Source</dt><dd><a href="@_livre.UrlNotice" target="_blank" rel="noopener noreferrer">Voir la notice source</a></dd></div>
}
</dl>
</div>
</div>
@@ -329,6 +334,7 @@ else
TypeDocument = livre.TypeDocument,
Statut = livre.Statut,
CoverUrl = livre.CoverUrl,
UrlNotice = livre.UrlNotice,
};
/// <summary>
+1
View File
@@ -646,6 +646,7 @@ else
Auteurs = candidat.Auteurs.Select(a => new AuteurSaisi(a)).ToList(),
Editeur = candidat.Editeur,
CoverUrl = candidat.CoverUrl,
UrlNotice = candidat.UrlNotice,
};
var resultat = await Api.CreerAsync(saisie);
_enCours = false;
@@ -240,6 +240,41 @@ public sealed class ServiceLivresApi(HttpClient http, CacheHorsLigne cache, Etat
return instantane?.Donnees.FirstOrDefault(a => a.Id == id);
}
public async Task<ResultatRenommageAuteur?> RenommerAuteurAsync(
int id, string nom, bool confirmerFusion = false, CancellationToken ct = default)
{
if (!reseau.EnLigne)
{
return null;
}
var suffixe = confirmerFusion ? "?confirmerFusion=true" : string.Empty;
try
{
var reponse = await http.PutAsJsonAsync(
$"api/auteurs/{id}{suffixe}", new RenommerAuteur(nom), Json, ct);
reseau.SignalerSuccesReseau();
if (reponse.StatusCode == HttpStatusCode.NotFound)
{
return null;
}
if (reponse.StatusCode == HttpStatusCode.Conflict
|| reponse.IsSuccessStatusCode)
{
return await LireAsync<ResultatRenommageAuteur>(reponse, ct);
}
return null;
}
catch (HttpRequestException)
{
reseau.SignalerEchecReseau();
return null;
}
}
/// <summary>
/// Rapprochements d'auteurs ambigus, que le serveur refuse d'appliquer seul.
/// </summary>