Refactoring gestione sessione e persistenza impostazioni

Introdotto `SessionService` per centralizzare la gestione della
sessione utente, migliorando la separazione delle responsabilità
e la testabilità. Risolto il problema del caricamento del cookie
di autenticazione all'avvio e garantita la persistenza delle
checkbox di esportazione (`IncludeMetadata`, `RemoveAfterExport`,
`OverwriteExisting`).

Ottimizzata la gestione della barra degli indirizzi del browser
con aggiornamenti locali immediati. Applicato il pattern "Load ?
Modify ? Save" per il salvataggio delle impostazioni, migliorando
la simmetria e la leggibilità del codice. Logging centralizzato
e semplificato per eventi rilevanti.

Aggiornata la documentazione per riflettere i cambiamenti e
verificati i test per garantire il corretto funzionamento.
This commit is contained in:
2025-11-24 12:00:13 +01:00
parent ee67bedc31
commit 62d5cebf9c
22 changed files with 5244 additions and 299 deletions
+12 -2
View File
@@ -88,7 +88,8 @@ namespace AutoBidder.Services
if (!_auctions.Any(a => a.AuctionId == auction.AuctionId))
{
_auctions.Add(auction);
OnLog?.Invoke($"[+] Asta aggiunta: {auction.Name} (ID: {auction.AuctionId})");
// ? RIMOSSO: Log ridondante - viene già loggato da MainWindow con defaults e stato
// OnLog?.Invoke($"[+] Asta aggiunta: {auction.Name} (ID: {auction.AuctionId})");
}
}
}
@@ -101,7 +102,8 @@ namespace AutoBidder.Services
if (auction != null)
{
_auctions.Remove(auction);
OnLog?.Invoke($"[-] Asta rimossa: {auction.Name}");
// ? RIMOSSO: Log ridondante - viene già loggato da MainWindow con più dettagli
// OnLog?.Invoke($"[-] Asta rimossa: {auction.Name}");
}
}
}
@@ -552,5 +554,13 @@ namespace AutoBidder.Services
{
return await _apiClient.PlaceBidAsync(auction.AuctionId, auction.OriginalUrl);
}
/// <summary>
/// Espone ApiClient per SessionService
/// </summary>
public BidooApiClient GetApiClient()
{
return _apiClient;
}
}
}
+226
View File
@@ -0,0 +1,226 @@
using System;
using System.Threading.Tasks;
using AutoBidder.Models;
namespace AutoBidder.Services
{
/// <summary>
/// Servizio centralizzato per gestione sessione utente
/// Responsabile di: Load, Save, Validate, Activate
///
/// PATTERN: Single Responsibility + Dependency Injection
/// </summary>
public class SessionService
{
private readonly BidooApiClient _apiClient;
private BidooSession? _currentSession;
public event Action<string>? OnLog;
public event Action<BidooSession>? OnSessionChanged;
public SessionService(BidooApiClient apiClient)
{
_apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
}
/// <summary>
/// Carica sessione salvata da disco (se esiste)
/// </summary>
public BidooSession? LoadSession()
{
try
{
var session = SessionManager.LoadSession();
if (session != null && session.IsValid)
{
_currentSession = session;
return session;
}
return null;
}
catch (Exception ex)
{
OnLog?.Invoke($"[SESSION ERROR] Caricamento fallito: {ex.Message}");
return null;
}
}
/// <summary>
/// Salva sessione su disco (crittografata con DPAPI)
/// </summary>
public bool SaveSession(BidooSession session)
{
try
{
if (session == null || !session.IsValid)
{
OnLog?.Invoke("[SESSION ERROR] Sessione non valida, impossibile salvare");
return false;
}
var success = SessionManager.SaveSession(session);
if (success)
{
_currentSession = session;
OnLog?.Invoke($"[SESSION] Salvata sessione per: {session.Username}");
OnSessionChanged?.Invoke(session);
}
else
{
OnLog?.Invoke("[SESSION ERROR] Salvataggio fallito");
}
return success;
}
catch (Exception ex)
{
OnLog?.Invoke($"[SESSION ERROR] Salvataggio fallito: {ex.Message}");
return false;
}
}
/// <summary>
/// Valida e attiva sessione: verifica che il cookie funzioni
///
/// QUESTO È IL METODO PRINCIPALE da usare:
/// - All'avvio per validare sessione salvata
/// - Dopo inserimento/modifica cookie
///
/// GARANTISCE l'ordine corretto delle chiamate:
/// 1. Inizializza cookie nel client HTTP
/// 2. Attiva sessione server-side (buy_bids.php)
/// 3. Recupera e valida dati utente
/// </summary>
public async Task<SessionValidationResult> ValidateAndActivateSessionAsync(string cookieString, string? username = null)
{
var result = new SessionValidationResult();
try
{
// Step 1: Inizializza cookie nel client HTTP
_apiClient.InitializeSessionWithCookie(cookieString, username ?? string.Empty);
// Step 2: CHIAVE - Attiva sessione server-side
// Questo chiama buy_bids.php che:
// - Crea stato sessione server
// - Valida il cookie
// - Restituisce dati utente
var activationSuccess = await _apiClient.UpdateUserInfoAsync();
if (!activationSuccess)
{
result.Success = false;
result.ErrorMessage = "Impossibile attivare sessione - cookie potrebbe essere scaduto o non valido";
OnLog?.Invoke($"[SESSION ERROR] {result.ErrorMessage}");
return result;
}
// Step 3: Recupera dati utente aggiornati
var session = _apiClient.GetSession();
if (session == null || string.IsNullOrEmpty(session.Username))
{
result.Success = false;
result.ErrorMessage = "Sessione attivata ma dati utente non disponibili";
OnLog?.Invoke($"[SESSION ERROR] {result.ErrorMessage}");
return result;
}
// Step 4: Successo!
result.Success = true;
result.Session = session;
_currentSession = session;
OnLog?.Invoke($"[SESSION OK] Validata e attiva: {session.Username}, {session.RemainingBids} puntate");
OnSessionChanged?.Invoke(session);
return result;
}
catch (Exception ex)
{
result.Success = false;
result.ErrorMessage = $"Eccezione durante validazione: {ex.Message}";
OnLog?.Invoke($"[SESSION EXCEPTION] {ex.Message}");
return result;
}
}
/// <summary>
/// Ottiene sessione corrente in memoria
/// </summary>
public BidooSession? GetCurrentSession()
{
return _currentSession;
}
/// <summary>
/// Aggiorna dati utente (puntate residue, credito, ecc.)
/// Da chiamare periodicamente o dopo ogni puntata
/// </summary>
public async Task<bool> RefreshUserInfoAsync()
{
try
{
OnLog?.Invoke("[SESSION] Refresh dati utente...");
var success = await _apiClient.UpdateUserInfoAsync();
if (success)
{
_currentSession = _apiClient.GetSession();
if (_currentSession != null)
{
OnLog?.Invoke($"[SESSION] Dati aggiornati: {_currentSession.Username}, {_currentSession.RemainingBids} puntate");
OnSessionChanged?.Invoke(_currentSession);
}
}
else
{
OnLog?.Invoke("[SESSION WARN] Refresh fallito");
}
return success;
}
catch (Exception ex)
{
OnLog?.Invoke($"[SESSION ERROR] Refresh fallito: {ex.Message}");
return false;
}
}
/// <summary>
/// Pulisce sessione corrente (memoria + disco)
/// </summary>
public void ClearSession()
{
_currentSession = null;
SessionManager.ClearSession();
OnLog?.Invoke("[SESSION] Sessione pulita");
}
}
/// <summary>
/// Risultato della validazione sessione
/// </summary>
public class SessionValidationResult
{
/// <summary>
/// True se la validazione è riuscita
/// </summary>
public bool Success { get; set; }
/// <summary>
/// Sessione validata e attiva (null se validazione fallita)
/// </summary>
public BidooSession? Session { get; set; }
/// <summary>
/// Messaggio di errore (null se validazione riuscita)
/// </summary>
public string? ErrorMessage { get; set; }
}
}