diff --git a/app/Controllers/UpdateController.php b/app/Controllers/UpdateController.php index 90cec16..cafe926 100644 --- a/app/Controllers/UpdateController.php +++ b/app/Controllers/UpdateController.php @@ -115,9 +115,13 @@ class UpdateController extends Controller if (!$hasMigrations) { try { $notificationService = new NotificationService(); + // For hotfixes the "to_version" is a commit SHA (e.g. "4371f17"), + // not a semver string. Pass the current app version so the + // notification reads "v1.1.3 has been updated" instead of "v4371f17". + $notifyToVersion = ($type === 'hotfix') ? $fromVersion : $toVersion; $notificationService->notifyAdminsUpgrade( $fromVersion, - $toVersion, + $notifyToVersion, 0, !empty($result['composer_manual_required']) ); diff --git a/app/Services/NotificationService.php b/app/Services/NotificationService.php index 99124d2..d45e6c2 100644 --- a/app/Services/NotificationService.php +++ b/app/Services/NotificationService.php @@ -573,7 +573,13 @@ class NotificationService */ public function notifySystemUpgrade(int $userId, string $fromVersion, string $toVersion, int $migrationsCount, bool $composerManualRequired = false): void { - $message = "Domain Monitor upgraded from v{$fromVersion} to v{$toVersion} ({$migrationsCount} migration" . ($migrationsCount > 1 ? 's' : '') . " applied)"; + $migrationLabel = $migrationsCount . ' migration' . ($migrationsCount !== 1 ? 's' : '') . ' applied'; + if ($fromVersion === $toVersion) { + // Hotfix: same version, just file updates + $message = "Domain Monitor v{$toVersion} has been updated ({$migrationLabel})"; + } else { + $message = "Domain Monitor upgraded from v{$fromVersion} to v{$toVersion} ({$migrationLabel})"; + } if ($composerManualRequired) { $message .= ". Composer could not be run here (e.g. exec disabled). If dependencies changed, run \"composer install --no-dev\" manually via SSH or Terminal."; } diff --git a/app/Services/UpdateService.php b/app/Services/UpdateService.php index b671cf0..ebe1291 100644 --- a/app/Services/UpdateService.php +++ b/app/Services/UpdateService.php @@ -243,6 +243,9 @@ class UpdateService ? ($this->settingModel->getValue('latest_available_version') ?: $this->settingModel->getAppVersion()) : ($this->settingModel->getValue('latest_remote_sha') ? substr($this->settingModel->getValue('latest_remote_sha'), 0, 7) : 'latest'); + // Clear cached update state so the UI no longer shows a stale "update available" card + $this->clearUpdateCache(); + $this->logger->endOperation('Application Update', [ 'success' => true, 'files_updated' => $filesUpdated, @@ -386,6 +389,24 @@ class UpdateService // Private: Cache methods // ======================================================================== + /** + * Clear all cached update-check state so the UI no longer shows stale "update available" info. + * Called after a successful update is applied. + */ + private function clearUpdateCache(): void + { + $this->settingModel->setValue('last_update_check', null); + $this->settingModel->setValue('commits_behind_count', '0'); + $this->settingModel->setValue('latest_remote_sha', ''); + $this->settingModel->setValue('latest_release_notes', ''); + $this->settingModel->setValue('latest_release_url', ''); + $this->settingModel->setValue('latest_release_published_at', ''); + // Note: latest_available_version is kept — it's used by the view to compare + // against current_version. After migrations bump app_version, the comparison + // will no longer show an update. Clearing it could cause issues if migrations + // haven't run yet and the user reloads the page. + } + private function isCacheValid(string $lastCheckTimestamp): bool { $lastCheck = strtotime($lastCheckTimestamp);