diff --git a/public/assets/app.js b/public/assets/app.js index ed26f7e..0534a93 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -4922,7 +4922,13 @@ function renderBackups() { ? `Local` : `Distant (SSH)`; - const versionBadge = `v${escapeHtml(b.version || '1.2.0')}`; + const versionBadge = `v${escapeHtml(b.version || '1.6.2')}`; + let srcBadge = ''; + if (b.source === 'pre-update') { + srcBadge = `Pré-MàJ`; + } else if (b.source === 'scheduled') { + srcBadge = `Auto`; + } return ` @@ -4933,6 +4939,7 @@ function renderBackups() { ${escapeHtml(b.filename)} ${versionBadge} + ${srcBadge} ${escapeHtml(b.date_formatted)} diff --git a/scripts/update.sh b/scripts/update.sh index 519598f..1a48da7 100755 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -81,15 +81,18 @@ fi echo -e "\n${C_YELLOW}-> Mise à jour vers la version v${REMOTE_VER}...${C_RESET}" -# 1. Sauvegarde préventive automatique -echo -e "${C_GRAY}[1/6] Création d'une sauvegarde préventive du système...${C_RESET}" -mkdir -p "$APP_DIR/storage/backups" -BACKUP_DATE=$(date +%Y%m%d_%H%M%S) -BACKUP_FILE="$APP_DIR/storage/backups/pre-update-${BACKUP_DATE}.tar.gz" -tar -czf "$BACKUP_FILE" \ - -C "$APP_DIR/storage" database.sqlite \ - -C /etc/asterisk pjsip.custom.conf extensions.custom.conf 2>/dev/null || true -echo -e "${C_GREEN} ✓ Sauvegarde de sécurité créée : $(basename "$BACKUP_FILE")${C_RESET}" +# 1. Sauvegarde préventive automatique (Disaster Recovery complète) +echo -e "${C_GRAY}[1/6] Création d'une sauvegarde préventive du système (Disaster Recovery)...${C_RESET}" +php -r ' +require_once "/var/www/nexus-pbx/src/Database.php"; +require_once "/var/www/nexus-pbx/src/BackupManager.php"; +try { + $res = App\BackupManager::createBackup("pre-update"); + echo " ✓ Sauvegarde Disaster Recovery créée : " . $res["filename"] . " (" . $res["size_formatted"] . ")\n"; +} catch (\Throwable $e) { + echo " ! Avertissement sauvegarde préventive : " . $e->getMessage() . "\n"; +} +' || true # 2. Application des derniers fichiers de code Git echo -e "${C_GRAY}[2/6] Déploiement des nouveaux fichiers de code...${C_RESET}" diff --git a/src/BackupManager.php b/src/BackupManager.php index dce7de4..16125db 100644 --- a/src/BackupManager.php +++ b/src/BackupManager.php @@ -11,7 +11,22 @@ use InvalidArgumentException; class BackupManager { public const BACKUP_DIR = '/var/www/nexus-pbx/storage/system_backups'; - public const VERSION = '1.2.0'; + public const VERSION = '1.6.2'; + + /** + * Retourne dynamiquement la version courante de NexusPBX lue depuis version.json + */ + public static function getAppVersion(): string + { + $vFile = dirname(__DIR__) . '/version.json'; + if (file_exists($vFile)) { + $data = json_decode((string)file_get_contents($vFile), true); + if (!empty($data['version'])) { + return (string)$data['version']; + } + } + return self::VERSION; + } /** * Initialise le répertoire des sauvegardes. @@ -182,7 +197,8 @@ class BackupManager } $timestamp = date('Ymd_His'); - $filename = "nexus_backup_v" . self::VERSION . "_{$timestamp}.tar.gz"; + $currentVer = self::getAppVersion(); + $filename = "nexus_backup_v{$currentVer}_{$timestamp}.tar.gz"; $localArchivePath = self::BACKUP_DIR . '/' . $filename; // 2. Préparation du dossier de staging @@ -268,7 +284,7 @@ class BackupManager // G. Création du Manifeste $manifest = [ - 'nexus_version' => self::VERSION, + 'nexus_version' => $currentVer, 'created_at' => date('c'), 'timestamp' => time(), 'filename' => $filename, @@ -360,6 +376,14 @@ class BackupManager // Tenter de lire le manifest depuis l'archive sans l'extraire entièrement $manifest = self::readManifestFromTar($file); + $archiveVer = $manifest['nexus_version'] ?? null; + if (!$archiveVer && preg_match('/_v([0-9]+\.[0-9]+(?:\.[0-9]+)?)/', $name, $vm)) { + $archiveVer = $vm[1]; + } + if (!$archiveVer) { + $archiveVer = self::getAppVersion(); + } + $backups[] = [ 'filename' => $name, 'storage_type' => 'local', @@ -367,7 +391,7 @@ class BackupManager 'size_formatted' => self::formatBytes($size), 'timestamp' => $mtime, 'date_formatted' => date('d/m/Y H:i:s', $mtime), - 'version' => $manifest['nexus_version'] ?? self::VERSION, + 'version' => $archiveVer, 'source' => $manifest['source'] ?? 'local', 'is_local' => true, ]; @@ -807,6 +831,13 @@ class BackupManager $name = basename($fullPath); if (str_ends_with($name, '.tar.gz')) { + $remoteVer = null; + if (preg_match('/_v([0-9]+\.[0-9]+(?:\.[0-9]+)?)/', $name, $vm)) { + $remoteVer = $vm[1]; + } + if (!$remoteVer) { + $remoteVer = self::getAppVersion(); + } $results[] = [ 'filename' => $name, 'storage_type' => 'ssh', @@ -814,7 +845,7 @@ class BackupManager 'size_formatted' => self::formatBytes($size), 'timestamp' => $timestamp > 0 ? $timestamp : time(), 'date_formatted' => date('d/m/Y H:i:s', $timestamp > 0 ? $timestamp : time()), - 'version' => self::VERSION, + 'version' => $remoteVer, 'source' => 'distant (SSH)', 'is_local' => false, ]; diff --git a/version.json b/version.json index a81ea33..92da145 100644 --- a/version.json +++ b/version.json @@ -1,16 +1,15 @@ { - "version": "1.6.1", + "version": "1.6.2", "codename": "Helios", "release_date": "2026-11-05", "min_php_version": "8.2", "changelog": [ + "Sauvegarde & Restauration : versionnage dynamique automatique basé sur la version installée (résolution du tag figé v1.2.0)", + "Mises à jour système OTA : déclenchement garanti d'une sauvegarde Disaster Recovery complète pré-mise à jour (visible et restaurable dans l'interface)", + "Interface Sauvegardes : nouveau badge identifiant la source (Pré-MàJ, Auto, Manuel)", "Identité visuelle officielle : intégration du nouveau logo NexusPBX 3D haute définition épuré et du favicon", "Nouveau slogan télécom : « Supervision & Téléphonie IP • Powered by Asterisk »", - "Amélioration des scripts d'installation et de mise à jour : initialisation automatique des permissions et ACLs du module CDR (Master.csv)", - "Nouveau module Journal d'Appels & CDR : traçabilité complète des flux entrants, sortants, internes et services avec détection automatique des Trunks SIP et postes associés", - "Filtres multicritères CDR en temps réel (période, direction, statut décroché/manqué, recherche textuelle) et export CSV Excel", - "Optimisation TLS SIP PJSIP : négociation universelle TLSv1.2/TLSv1.3 (method=sslv23)", - "Suppression de CertificateRequest en mode TLS standard pour compatibilité totale avec les téléphones IP Yealink, Fanvil et Grandstream", - "Plafond d'expiration d'enregistrement SIP standard (maximum_expiration = 300s, default = 120s) garantissant la reconnexion automatique rapide de tous les postes" + "Module Journal d'Appels & CDR avec filtres et export CSV", + "Support universel TLSv1.2/TLSv1.3 et suppression CertificateRequest pour postes Yealink" ] }