Compare commits
3
Commits
56be0ab37a
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfc71a7763 | ||
|
|
f99cf440a7 | ||
|
|
5cb3900c67 |
No files matched your search
@@ -2621,6 +2621,7 @@ try {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'run_update':
|
case 'run_update':
|
||||||
|
@set_time_limit(300);
|
||||||
$output = [];
|
$output = [];
|
||||||
$code = 0;
|
$code = 0;
|
||||||
exec("sudo /var/www/nexus-pbx/scripts/update.sh 2>&1", $output, $code);
|
exec("sudo /var/www/nexus-pbx/scripts/update.sh 2>&1", $output, $code);
|
||||||
|
|||||||
+44
-26
@@ -6330,7 +6330,12 @@ async function checkSystemUpdate(notify = false) {
|
|||||||
if (pingDot) pingDot.classList.remove('hidden');
|
if (pingDot) pingDot.classList.remove('hidden');
|
||||||
|
|
||||||
if (changelogList && Array.isArray(data.changelog) && data.changelog.length > 0) {
|
if (changelogList && Array.isArray(data.changelog) && data.changelog.length > 0) {
|
||||||
changelogList.innerHTML = data.changelog.map(item => `<li>${escapeHtml(item)}</li>`).join('');
|
changelogList.innerHTML = data.changelog.flatMap(item => {
|
||||||
|
if (item && typeof item === 'object' && Array.isArray(item.changes)) {
|
||||||
|
return item.changes.map(c => `<li>${escapeHtml(String(c))}</li>`);
|
||||||
|
}
|
||||||
|
return [`<li>${escapeHtml(String(item ?? ''))}</li>`];
|
||||||
|
}).join('');
|
||||||
if (changelogContainer) changelogContainer.classList.remove('hidden');
|
if (changelogContainer) changelogContainer.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -6412,11 +6417,29 @@ async function executeSystemUpdate() {
|
|||||||
|
|
||||||
showToast("Mise à jour en cours d'exécution en arrière-plan...", 'info');
|
showToast("Mise à jour en cours d'exécution en arrière-plan...", 'info');
|
||||||
|
|
||||||
|
// Pause du polling métriques pour éviter un 502 Nginx pendant le reload php-fpm/nginx
|
||||||
|
stopMetricsPolling();
|
||||||
|
|
||||||
// Purge préventive du cache local
|
// Purge préventive du cache local
|
||||||
localStorage.removeItem('nexus_update_last_check_ts');
|
localStorage.removeItem('nexus_update_last_check_ts');
|
||||||
localStorage.removeItem('nexus_update_cached_data');
|
localStorage.removeItem('nexus_update_cached_data');
|
||||||
|
|
||||||
function finalizeUpdateSuccess(newVer) {
|
async function probeUpdateReady(maxAttempts = 6, delayMs = 1500) {
|
||||||
|
for (let i = 0; i < maxAttempts; i++) {
|
||||||
|
await new Promise(r => setTimeout(r, delayMs));
|
||||||
|
try {
|
||||||
|
const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now());
|
||||||
|
if (!probeRes.ok) continue;
|
||||||
|
const probeData = await probeRes.json();
|
||||||
|
if (probeData && probeData.success && probeData.current_version) {
|
||||||
|
return probeData;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function finalizeUpdateSuccess(newVer) {
|
||||||
newVer = String(newVer || '').replace(/^v/, '');
|
newVer = String(newVer || '').replace(/^v/, '');
|
||||||
localStorage.setItem('nexus_update_last_check_ts', Date.now().toString());
|
localStorage.setItem('nexus_update_last_check_ts', Date.now().toString());
|
||||||
localStorage.setItem('nexus_update_cached_data', JSON.stringify({
|
localStorage.setItem('nexus_update_cached_data', JSON.stringify({
|
||||||
@@ -6449,10 +6472,11 @@ async function executeSystemUpdate() {
|
|||||||
btnModalConfirm.innerHTML = '✓ Mise à jour terminée ! Rechargement...';
|
btnModalConfirm.innerHTML = '✓ Mise à jour terminée ! Rechargement...';
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
// Attendre que le reload différé php-fpm/nginx soit terminé avant de recharger la page
|
||||||
closeUpdateConfirmModal();
|
await new Promise(r => setTimeout(r, 2500));
|
||||||
window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now();
|
await probeUpdateReady(5, 1000);
|
||||||
}, 1800);
|
closeUpdateConfirmModal();
|
||||||
|
window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -6476,18 +6500,15 @@ async function executeSystemUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Si la réponse n'était pas un JSON valide ou a été interrompue par le rechargement de php-fpm/nginx,
|
// Si la réponse n'était pas un JSON valide ou a été interrompue par le rechargement de php-fpm/nginx,
|
||||||
// on sonde le serveur pour vérifier si la mise à jour a en réalité bien été appliquée sur le disque
|
// on sonde le serveur à plusieurs reprises pour laisser Nginx/PHP-FPM terminer leur reload
|
||||||
await new Promise(r => setTimeout(r, 2000));
|
const probeData = await probeUpdateReady(6, 1500);
|
||||||
try {
|
if (probeData) {
|
||||||
const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now());
|
await finalizeUpdateSuccess(probeData.current_version);
|
||||||
const probeData = await probeRes.json();
|
return;
|
||||||
if (probeData && probeData.success && probeData.current_version) {
|
}
|
||||||
finalizeUpdateSuccess(probeData.current_version);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
|
|
||||||
// En cas d'échec réel avéré
|
// En cas d'échec réel avéré
|
||||||
|
startMetricsPolling();
|
||||||
closeUpdateConfirmModal();
|
closeUpdateConfirmModal();
|
||||||
const errMsg = (data && (data.output || data.message)) ? (data.output || data.message) : (rawText.slice(0, 150) || "Erreur inconnue");
|
const errMsg = (data && (data.output || data.message)) ? (data.output || data.message) : (rawText.slice(0, 150) || "Erreur inconnue");
|
||||||
alert("Erreur lors de la mise à jour :\n\n" + errMsg);
|
alert("Erreur lors de la mise à jour :\n\n" + errMsg);
|
||||||
@@ -6503,17 +6524,14 @@ async function executeSystemUpdate() {
|
|||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// En cas d'interruption réseau du socket (Safari WebKit DOMException ou timeout),
|
// En cas d'interruption réseau du socket (Safari WebKit DOMException ou timeout),
|
||||||
// on vérifie avant d'alerter si le serveur a quand même réussi à déployer les fichiers
|
// on vérifie à plusieurs reprises si le serveur a quand même réussi à déployer les fichiers
|
||||||
await new Promise(r => setTimeout(r, 2000));
|
const probeData = await probeUpdateReady(6, 1500);
|
||||||
try {
|
if (probeData) {
|
||||||
const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now());
|
await finalizeUpdateSuccess(probeData.current_version);
|
||||||
const probeData = await probeRes.json();
|
return;
|
||||||
if (probeData && probeData.success && probeData.current_version) {
|
}
|
||||||
finalizeUpdateSuccess(probeData.current_version);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
|
|
||||||
|
startMetricsPolling();
|
||||||
closeUpdateConfirmModal();
|
closeUpdateConfirmModal();
|
||||||
alert("Erreur réseau lors de la mise à jour : " + (e.message || "Connexion interrompue"));
|
alert("Erreur réseau lors de la mise à jour : " + (e.message || "Connexion interrompue"));
|
||||||
if (btnRun) {
|
if (btnRun) {
|
||||||
|
|||||||
+12
-5
@@ -261,7 +261,7 @@ if [ -t 1 ]; then
|
|||||||
systemctl reload nginx 2>/dev/null || true
|
systemctl reload nginx 2>/dev/null || true
|
||||||
fail2ban-client reload >/dev/null 2>&1 || true
|
fail2ban-client reload >/dev/null 2>&1 || true
|
||||||
else
|
else
|
||||||
(nohup bash -c "sleep 2 && (systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true); systemctl reload nginx 2>/dev/null || true; fail2ban-client reload >/dev/null 2>&1 || true" >/dev/null 2>&1 &)
|
(nohup bash -c "sleep 1 && (systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true); systemctl reload nginx 2>/dev/null || true; fail2ban-client reload >/dev/null 2>&1 || true" </dev/null >/dev/null 2>&1 &)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
NEW_VER="Inconnue"
|
NEW_VER="Inconnue"
|
||||||
@@ -279,10 +279,17 @@ echo ""
|
|||||||
if [ -f "$APP_DIR/version.json" ]; then
|
if [ -f "$APP_DIR/version.json" ]; then
|
||||||
echo -e "${C_CYAN}${C_BOLD}Nouveautés de cette version :${C_RESET}"
|
echo -e "${C_CYAN}${C_BOLD}Nouveautés de cette version :${C_RESET}"
|
||||||
php -r '
|
php -r '
|
||||||
$v = json_decode(file_get_contents("/var/www/nexus-pbx/version.json"), true);
|
$v = json_decode(@file_get_contents("/var/www/nexus-pbx/version.json"), true);
|
||||||
if (!empty($v["changelog"])) {
|
if (!empty($v["changelog"]) && is_array($v["changelog"])) {
|
||||||
foreach ($v["changelog"] as $line) {
|
$first = $v["changelog"][0];
|
||||||
echo " • " . $line . "\n";
|
if (is_array($first) && !empty($first["changes"])) {
|
||||||
|
foreach ($first["changes"] as $line) {
|
||||||
|
echo " • " . $line . "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($v["changelog"] as $line) {
|
||||||
|
if (is_string($line)) echo " • " . $line . "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'
|
'
|
||||||
|
|||||||
@@ -95,12 +95,14 @@ class PhonebookManager
|
|||||||
$existing = $findStmt->fetch(PDO::FETCH_ASSOC);
|
$existing = $findStmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if ($existing) {
|
if ($existing) {
|
||||||
|
$existingEmail = trim((string)($existing['email'] ?? ''));
|
||||||
|
$finalEmail = $existingEmail !== '' ? $existingEmail : $email;
|
||||||
$updateStmt->execute([
|
$updateStmt->execute([
|
||||||
':id' => (int)$existing['id'],
|
':id' => (int)$existing['id'],
|
||||||
':ext_id' => $extId,
|
':ext_id' => $extId,
|
||||||
':name' => $extName,
|
':name' => $extName,
|
||||||
':num' => $extNum,
|
':num' => $extNum,
|
||||||
':email' => $email,
|
':email' => $finalEmail,
|
||||||
':grp' => $group,
|
':grp' => $group,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+6
-16
@@ -1,24 +1,14 @@
|
|||||||
{
|
{
|
||||||
"version": "2.7.0",
|
"version": "2.7.3",
|
||||||
"codename": "Pulsar UCP",
|
"codename": "Pulsar UCP",
|
||||||
"release_date": "2026-11-12",
|
"release_date": "2026-11-12",
|
||||||
"min_php_version": "8.2",
|
"min_php_version": "8.2",
|
||||||
"changelog": [
|
"changelog": [
|
||||||
{
|
"Correctif v2.7.3 : conservation de l'adresse email renseignée sur un contact interne de l'Annuaire lors de la synchronisation des postes",
|
||||||
"version": "2.7.0",
|
"Correctif v2.7.2 : formatage uniforme du changelog dans version.json (suppression de [object Object] dans la fiche de mise à jour)",
|
||||||
"date": "2026-11-12",
|
"Correctif v2.7.1 : suppression de l'erreur Nginx 502 transitoire après mise à jour 1-Clic (pause du polling métriques, sonde multi-essais avant rechargement)",
|
||||||
"changes": [
|
"Nouveauté v2.7.0 : logo spécifique optionnel pour le portail UCP (thème clair), avec repli automatique sur le logo principal puis NexusPBX",
|
||||||
"Branding UCP : Ajout d'un logo spécifique optionnel pour le portail UCP (thème clair), avec repli automatique sur le logo principal puis sur le logo NexusPBX par défaut"
|
"UI v2.6.7 : remplacement de l'ensemble des icônes emoji par des icônes vectorielles SVG uniformes sur Admin & UCP (sans modifier le menu latéral Admin)",
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "2.6.7",
|
|
||||||
"date": "2026-11-12",
|
|
||||||
"changes": [
|
|
||||||
"UI Admin & UCP : Remplacement de l'ensemble des icônes emoji par des icônes vectorielles SVG uniformes (style Heroicons), sans modifier le menu latéral Admin",
|
|
||||||
"Correction d'un problème de syntaxe JS sur le badge d'avertissement TLS dans app.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"UI v2.6.6 : menu déroulant personnalisé sombre avec icônes SVG Heroicons pour toutes les destinations d'appel (sans emojis natifs)",
|
"UI v2.6.6 : menu déroulant personnalisé sombre avec icônes SVG Heroicons pour toutes les destinations d'appel (sans emojis natifs)",
|
||||||
"UI v2.6.5 : refonte des intitulés de destinations audio (Musique d'attente & Annonce vocale en boucle continue), nouveau wallpaper clair UCP et placeholder générique",
|
"UI v2.6.5 : refonte des intitulés de destinations audio (Musique d'attente & Annonce vocale en boucle continue), nouveau wallpaper clair UCP et placeholder générique",
|
||||||
"Correctif v2.6.4 : prise en charge multi-groupes dans l'annuaire UCP & Admin (un poste appartenant à plusieurs groupes apparaît bien dans chacun des onglets correspondants)",
|
"Correctif v2.6.4 : prise en charge multi-groupes dans l'annuaire UCP & Admin (un poste appartenant à plusieurs groupes apparaît bien dans chacun des onglets correspondants)",
|
||||||
|
|||||||
Reference in new issue
Block a user