Files
PS_Launcher/server/tools/migrate.php
j.foucher efb53f079e v0.28.10 — Mode auto + settings lock par license + fix post-install state
Mode auto (auto-launch d'une version désignée au démarrage et après exit) :
 - Master toggle + version désignée via bouton AUTO (orange) sur chaque row
 - Countdown 5 s configurable avec popup d'annulation (StartAutoLaunchCountdown)
 - Args CLI passés à PROSERVE : opérateur tape juste le nom (autoconnect, login),
   le launcher ajoute -/=/quotes. Format produit identique à un .bat.
   Fix : passage de ArgumentList à Arguments string pour éviter le quotage auto
   .NET sur les args contenant '=' (cassait FParse::Value).
 - Garde-fou anti double-lancement : refuse de lancer si _runningProserve vivant
   OU IProcessLauncher.IsRunning() détecte une instance externe. Silent pour
   les triggers auto, popup pour les clics manuels.
 - Option « Attendre santé système » : countdown différé tant que les health
   checks ne sont pas tous OK (phase 1 du dialog avec liste des pending).

Settings lock par license (remplace l'ancien lock global manifest) :
 - Colonne settings_lock_password_hash sur table licenses (migration 003)
 - Backoffice : bouton 🔒 par license pour set/clear hash SHA-256
 - Payload /license/validate inclut settingsLockPasswordHash (v3 canonique)
 - 3-tier fallback signature : v3 → v2 → legacy pour compat cache offline
 - SettingsLockService : in-memory unlock state, gate l'expander Avancés
 - SettingsLockDialog : prompt mdp, persiste déverrouillé jusqu'au restart

Fix post-install : la row restait en visuel « Installing » jusqu'au prochain
Check Updates. Reset explicite row.State=InstalledIdle + _activeRow=null
AVANT le RebuildList post-install pour purger l'instance orpheline.

Migrations :
 - 002_channel_betas.sql réécrit en ALTER simples (DELIMITER cassait
   migrate.php qui split sur ';\n')
 - migrate.php tolère « Duplicate column/key name » comme idempotent

Strings (5 langues, ~25 nouvelles) :
 - Renomme « Relance automatique » → « Lancement automatique » (dialog
   utilisé pour les 3 entry points : clic, startup, post-exit)
 - Tooltips auto-mode, settings lock prompts, health wait phase, etc.

Bumps : 0.27.4 → 0.28.10 (csproj + .iss).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:56:55 +02:00

108 lines
3.5 KiB
PHP

<?php
/**
* Mini script de migration : applique tous les fichiers SQL présents dans
* migrations/ sur la base configurée dans api/config.php.
*
* Utilisable de deux façons :
* 1. En SSH : cd ~/www/PS_Launcher && php tools/migrate.php
* 2. Via le navigateur : https://asterionvr.com/PS_Launcher/tools/migrate.php
* (à supprimer après la première migration pour ne pas l'exposer)
*
* Le script est idempotent : les CREATE TABLE IF NOT EXISTS ne ré-écrasent pas
* les tables existantes. Tu peux donc le rejouer sans risque.
*/
declare(strict_types=1);
// Sécurité minimale : refuse l'exécution web si la config n'est pas là
$configPath = dirname(__DIR__) . '/api/config.php';
if (!is_file($configPath)) {
http_response_code(500);
header('Content-Type: text/plain; charset=utf-8');
echo "Erreur : api/config.php absent.\n";
exit(1);
}
$config = require $configPath;
// Mode CLI ou web ?
$cli = (PHP_SAPI === 'cli');
if (!$cli) {
header('Content-Type: text/plain; charset=utf-8');
}
function out(string $line): void {
echo $line . "\n";
if (PHP_SAPI !== 'cli') @ob_flush();
@flush();
}
out("=== PS_Launcher migrate.php ===");
out("DSN: " . $config['db']['dsn']);
try {
$pdo = new PDO(
$config['db']['dsn'],
$config['db']['username'],
$config['db']['password'],
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]
);
out("Connexion DB OK");
} catch (Exception $e) {
out("ÉCHEC connexion : " . $e->getMessage());
exit(2);
}
$migrationsDir = dirname(__DIR__) . '/migrations';
$files = glob("$migrationsDir/*.sql") ?: [];
sort($files);
if (!$files) {
out("Aucun fichier SQL dans $migrationsDir");
exit(0);
}
foreach ($files as $f) {
out("");
out("--- " . basename($f) . " ---");
$sql = file_get_contents($f);
// Découpe naïve sur les ';' suivis d'un saut de ligne (suffit pour notre schéma)
$statements = array_filter(array_map('trim', preg_split('/;\s*\n/', $sql) ?: []));
foreach ($statements as $stmt) {
if ($stmt === '' || str_starts_with($stmt, '--')) continue;
try {
$pdo->exec($stmt);
$first40 = substr(preg_replace('/\s+/', ' ', $stmt), 0, 60);
out("" . $first40 . "");
} catch (Exception $e) {
$msg = $e->getMessage();
// Tolérance idempotence : on n'aboie pas sur les ALTER qui re-touchent
// une colonne / un index existant. Permet de rejouer migrate.php sans
// risque sur une DB déjà partiellement / complètement migrée.
$idempotent = str_contains($msg, 'Duplicate column')
|| str_contains($msg, 'Duplicate key name')
|| str_contains($msg, "Can't DROP") // ALTER DROP COLUMN inexistante
|| str_contains($msg, 'check that column/key exists');
if ($idempotent) {
$first40 = substr(preg_replace('/\s+/', ' ', $stmt), 0, 60);
out(" ↺ (déjà appliqué) " . $first40 . "");
continue;
}
out(" ✘ ERREUR : " . $msg);
out(" Sur : " . substr($stmt, 0, 80) . "");
exit(3);
}
}
}
out("");
out("=== Migration terminée. Tables présentes ===");
$tables = $pdo->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN);
foreach ($tables as $t) out(" - $t");
if (!$cli) {
out("");
out("⚠ Pour la sécurité, supprime maintenant tools/migrate.php du serveur.");
}