Files
PS_Launcher/src/PSLauncher.Models/LocalConfig.cs
j.foucher 562b4e5ed0 v0.13.0 — Report tool : timestamped backups + manual revert
The previous deploy mechanism kept the old version under {target}.old
just long enough to swap, then deleted it — no way back if the new
report had a runtime bug only visible at use time.

Now each deploy keeps the previous active version under
{FolderName}.backup-yyyyMMdd-HHmmss/. The N most recent are kept
(MaxBackups, default 3) and older ones are pruned in best-effort.

UI in Settings → Avancés → Outil Report :
- "Conserver N backups" input (0 = no history, back to v0.12 behavior)
- List of backups with date + size + cryptic folder name + per-row "↶ Revert"
- Confirmation dialog: "Revert to {date}? The currently deployed
  version will itself be saved as a new backup, so you can switch back."

Implementation
- IReportToolDeployer: + ListBackupsAsync, + RevertAsync, + BackupInfo,
  + DeployStatus.BackupNotFound.
- ReportToolDeployer: deploy renames {target} → backup-{ts}; PruneOldBackups
  trims to MaxBackups; RevertAsync atomically swaps current ↔ chosen
  backup, the previous current becoming itself a fresh backup.
- ReportBackupViewModel + DataTemplate for the list rows.
- Strings: backup labels, "↶ Revert", confirmation message.

Caveats documented in the design discussion:
- Backups cover ONLY the report tool files. DB migrations are not reverted
  (irreversible). If a migration broke the schema, that's a separate fix.
- No HTTP-HEAD post-deploy auto-revert: too fragile for false positives.
  Revert stays a deliberate manual action.

Versions bumped to 0.13.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 09:15:09 +02:00

153 lines
6.8 KiB
C#

namespace PSLauncher.Models;
public sealed class LocalConfig
{
public int SchemaVersion { get; set; } = 1;
public string ServerBaseUrl { get; set; } = "https://example.com/PS_Launcher/api";
public string InstallRoot { get; set; } = string.Empty;
public string? LastLaunchedVersion { get; set; }
/// <summary>
/// Code de langue de l'UI : "auto" (suit la langue Windows), "fr", "en",
/// "zh", "th" ou "ar". Tout changement nécessite un redémarrage du launcher.
/// </summary>
public string Language { get; set; } = "auto";
/// <summary>
/// Nombre de connexions HTTP parallèles utilisées pour télécharger un build.
/// 1 = comportement legacy single-connection. 4-8 contourne le throttling
/// per-connection d'Apache/OVH mutualisé. 8 est un bon défaut.
/// </summary>
public int ParallelDownloadSegments { get; set; } = 8;
/// <summary>
/// Si false, ignore la vérification SHA-256 même si le manifest l'exige.
/// Utile sur les machines lentes ou pour gagner 30 s-3 min en fin de DL d'un gros build.
/// La sécurité repose alors uniquement sur la signature Ed25519 du manifest + HTTPS,
/// ce qui reste robuste.
/// </summary>
public bool VerifyDownloadHash { get; set; } = true;
/// <summary>
/// URL de l'outil de reporting local (page web embarquée dans le launcher,
/// onglet "Report"). Par défaut pointe vers l'install standard ASTERION
/// dans XAMPP. Surchargeable dans Settings → Avancés.
/// </summary>
public string ReportUrl { get; set; } = "http://localhost/ProserveReport/";
/// <summary>
/// URL de la documentation locale (onglet "Documentation"). Vide par défaut :
/// l'utilisateur peut pointer vers une URL locale ou web. Si vide, l'onglet
/// affiche un placeholder avec les liens vers les fichiers .pptx du dossier
/// d'install du launcher.
/// </summary>
public string DocumentationUrl { get; set; } = string.Empty;
public LicenseConfig License { get; set; } = new();
/// <summary>
/// Configuration du déploiement de l'outil Report (page web locale embarquée
/// dans l'onglet "Statistiques") vers la racine XAMPP htdocs.
/// Le launcher copie le dossier <c>_report/</c> bundled dans chaque ZIP
/// PROSERVE vers <c>{HtdocsRoot}\{FolderName}</c> à chaque install.
/// </summary>
public ReportToolConfig ReportTool { get; set; } = new();
/// <summary>
/// Connexion à la base MySQL locale (XAMPP) utilisée par PROSERVE pour ses
/// statistiques. Le launcher s'en sert pour appliquer les migrations bundled
/// dans <c>_migrations/</c> au moment de l'install d'une nouvelle version.
/// </summary>
public DatabaseConfig Database { get; set; } = new();
}
/// <summary>
/// Paramètres de connexion à la base MySQL locale. Les valeurs par défaut
/// correspondent à un XAMPP standard fraîchement installé. Override possible
/// via Settings → Base de données.
/// </summary>
public sealed class DatabaseConfig
{
public string Host { get; set; } = "localhost";
public uint Port { get; set; } = 3306;
public string User { get; set; } = "root";
/// <summary>
/// Mot de passe MySQL stocké chiffré DPAPI (CurrentUser scope) en base64.
/// Vide = pas de password (config XAMPP par défaut). NE PAS écrire en clair.
/// </summary>
public string? EncryptedPassword { get; set; }
/// <summary>
/// Nom de la base de données qui contient les tables de PROSERVE.
/// Default "proserveapi" — c'est le nom utilisé par le script d'install ASTERION
/// qui provisionne XAMPP sur les machines clients. À surcharger seulement si la DB
/// a été créée sous un autre nom.
/// </summary>
public string Database { get; set; } = "proserveapi";
/// <summary>
/// Si true, le launcher applique automatiquement les migrations SQL bundled
/// dans <c>_migrations/</c> de chaque ZIP, juste après l'extraction.
/// Sécurité : on n'applique JAMAIS sans cette opt-in (au cas où certains users
/// auraient une config DB exotique non gérée par le defaut).
/// </summary>
public bool AutoApplyMigrations { get; set; } = true;
}
/// <summary>
/// Paramètres de déploiement de l'outil Report local.
/// Le launcher cherche un sous-dossier <c>_report/</c> dans chaque ZIP PROSERVE
/// installé et le copie vers <c>{HtdocsRoot}\{FolderName}</c> via un rename
/// atomique (deploy en .new puis swap). L'URL de l'onglet Statistiques pointe
/// vers <c>http://localhost/{FolderName}/</c> ; les deux doivent matcher.
/// </summary>
public sealed class ReportToolConfig
{
public string HtdocsRoot { get; set; } = @"C:\xampp\htdocs";
public string FolderName { get; set; } = "ProserveReport";
public bool AutoDeploy { get; set; } = true;
/// <summary>
/// Nombre de backups horodatés à conserver dans htdocs après chaque deploy.
/// Format des dossiers : <c>{FolderName}.backup-yyyyMMdd-HHmmss</c>.
/// Permet le revert via Settings si le nouveau deploy a un bug visible.
/// 3 par défaut = couvre les dernières releases sans grossir trop le disque.
/// 0 = pas de backup (retourne au comportement v0.12.0).
/// </summary>
public int MaxBackups { get; set; } = 3;
}
public sealed class LicenseConfig
{
public string? EncryptedKey { get; set; }
/// <summary>
/// Date UTC de la dernière validation online réussie. Utilise <c>response.ServerTime</c>
/// (signé Ed25519) plutôt que l'horloge locale, donc non manipulable par l'utilisateur.
/// Sert de point de départ au calcul d'expiration du cache offline.
/// </summary>
public DateTime? LastValidationAt { get; set; }
public DateTime? CachedEntitlementUntil { get; set; }
public string? CachedOwnerName { get; set; }
/// <summary>
/// Statut tel que renvoyé par le serveur lors de la dernière validation : "valid",
/// "expired", "revoked", "invalid", "machine_limit_exceeded". Persisté pour qu'une
/// révocation effectuée pendant que le user est offline soit toujours visible
/// même après son expiration de cache local. Le calcul "valid → expired" basé
/// sur la date est aussi appliqué côté lecture (sanity) si le temps a passé.
/// </summary>
public string? CachedStatus { get; set; }
/// <summary>
/// Compteur monotone : date UTC la plus récente jamais observée par le launcher
/// sur cette machine. Mise à jour à chaque démarrage si <c>now</c> est postérieur.
/// Sert d'anti-rollback : si l'utilisateur recule l'horloge PC, on détecte
/// (now &lt; LastSeenUtc - grace) et on invalide le cache → forçage d'une
/// re-validation online la prochaine fois qu'il sera connecté.
/// </summary>
public DateTime? LastSeenUtc { get; set; }
}