From 4371f174c940a137ff63aad3f96ec8eea7afc8c7 Mon Sep 17 00:00:00 2001 From: Hosteroid Date: Wed, 11 Feb 2026 18:44:06 +0200 Subject: [PATCH] Capture app version and defer notifications Installer: capture the current app version (fromVersion) before running migrations, with a fallback for very old installs where settings may not exist. Re-read the app version after migrations to determine toVersion and only use migration-based detection as a fallback when the version didn't change. Update flow: only send admin upgrade notifications when there are no pending migrations. If migrations remain, the user is redirected to the installer which will send the correct notification after migrations complete. This prevents duplicate or incorrect upgrade notifications and ensures accurate from/to version reporting. --- app/Controllers/InstallerController.php | 41 +++++++++++++++---------- app/Controllers/UpdateController.php | 32 ++++++++++--------- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/app/Controllers/InstallerController.php b/app/Controllers/InstallerController.php index 55f0605..8debead 100644 --- a/app/Controllers/InstallerController.php +++ b/app/Controllers/InstallerController.php @@ -578,6 +578,16 @@ class InstallerController extends Controller $migrations = $this->getPendingMigrations(); $executed = []; + // Capture current app version BEFORE running migrations (so we know the real "from" version) + $fromVersion = null; + try { + $settingModel = new \App\Models\Setting(); + $fromVersion = $settingModel->getAppVersion(); + } catch (\Exception $e) { + // Settings table may not exist yet for very old installs + $fromVersion = '1.0.0'; + } + // Ensure migrations table exists for tracking $pdo->exec(" CREATE TABLE IF NOT EXISTS migrations ( @@ -639,24 +649,23 @@ class InstallerController extends Controller ]); try { + // Re-read the app version AFTER migrations to get the "to" version $settingModel = new \App\Models\Setting(); - $currentVersion = $settingModel->getAppVersion(); + $toVersion = $settingModel->getAppVersion(); - // Determine from/to versions based on migrations - $fromVersion = '1.0.0'; - $toVersion = '1.1.3'; - - // Detect version based on which migrations were run - if (in_array('025_add_update_system_v1.1.3.sql', $executed)) { - $toVersion = '1.1.3'; - } elseif (in_array('024_add_status_notifications_v1.1.2.sql', $executed)) { - $toVersion = '1.1.2'; - } elseif (in_array('022_add_pushover_channel_type.sql', $executed)) { - $toVersion = '1.1.1'; - } elseif (in_array('011_create_sessions_table.sql', $executed) || - in_array('012_link_remember_tokens_to_sessions.sql', $executed) || - in_array('013_create_user_notifications_table.sql', $executed)) { - $toVersion = '1.1.0'; + // Fallback: detect "to" version from which migrations were run + if ($toVersion === $fromVersion) { + if (in_array('025_add_update_system_v1.1.3.sql', $executed)) { + $toVersion = '1.1.3'; + } elseif (in_array('024_add_status_notifications_v1.1.2.sql', $executed)) { + $toVersion = '1.1.2'; + } elseif (in_array('022_add_pushover_channel_type.sql', $executed)) { + $toVersion = '1.1.1'; + } elseif (in_array('011_create_sessions_table.sql', $executed) || + in_array('012_link_remember_tokens_to_sessions.sql', $executed) || + in_array('013_create_user_notifications_table.sql', $executed)) { + $toVersion = '1.1.0'; + } } $notificationService = new \App\Services\NotificationService(); diff --git a/app/Controllers/UpdateController.php b/app/Controllers/UpdateController.php index 3ca519c..90cec16 100644 --- a/app/Controllers/UpdateController.php +++ b/app/Controllers/UpdateController.php @@ -109,20 +109,24 @@ class UpdateController extends Controller // Check for pending migrations after file update $hasMigrations = $this->updateService->hasPendingMigrations(); - // Notify admins - try { - $notificationService = new NotificationService(); - $notificationService->notifyAdminsUpgrade( - $fromVersion, - $toVersion, - 0, - !empty($result['composer_manual_required']) - ); - } catch (\Exception $e) { - // Non-critical - $this->logger->warning('Failed to send upgrade notification', [ - 'error' => $e->getMessage(), - ]); + // Only notify admins if there are NO pending migrations. + // When migrations are pending, the user is redirected to /install/update + // which sends the upgrade notification after migrations complete (with the correct count). + if (!$hasMigrations) { + try { + $notificationService = new NotificationService(); + $notificationService->notifyAdminsUpgrade( + $fromVersion, + $toVersion, + 0, + !empty($result['composer_manual_required']) + ); + } catch (\Exception $e) { + // Non-critical + $this->logger->warning('Failed to send upgrade notification', [ + 'error' => $e->getMessage(), + ]); + } } $message = "Update applied successfully! {$filesUpdated} file(s) updated.";