Fix: Update-Erkennung via Gitea-API + Fallback-Kette verbessert

- CheckUpdates: Gitea REST-API als neuen Fallback (funktioniert ohne Auth
  bei öffentlichem Repo), git ls-remote als weiterer Fallback
- $remoteFile vor dem Fallback-Block deklariert (undefined variable fix)
- UpdateCard + UpdatePage: latNorm aus Cache normalisieren → kein doppeltes "v"
- UpdateCard: openLogs()-Methode hinzugefügt (Logs-Button im Dashboard)
- Setup-Wizard: Zeitzone automatisch aus Browser-Intl erkannt (@script)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main v1.1.392
boban 2026-04-27 02:21:42 +02:00
parent fc7e1ed0f9
commit 5dc55a9d1c
4 changed files with 72 additions and 6 deletions

View File

@ -14,12 +14,15 @@ class CheckUpdates extends Command
$currentNorm = $this->readInstalledVersionNorm();
$currentRaw = $this->readInstalledVersionRaw() ?? ($currentNorm ? 'v'.$currentNorm : null);
$appPath = base_path();
$appPath = base_path();
$remoteFile = '/var/lib/mailwolt/version_remote';
// Fallback-Kette für Remote-Tags (erste funktionierende Methode gewinnt):
// 1. mailwolt-update --check-only (sudoers: mailwolt-update)
// 2. mailwolt-fetch-tags (sudoers: mailwolt-fetch-tags)
// 3. git fetch --tags als App-User direkt
// 3. Gitea/GitHub API (kein Auth nötig wenn Repo öffentlich)
// 4. git ls-remote (klappt wenn Credentials im git-Config)
// 5. git fetch --tags direkt
$updateBin = '/usr/local/sbin/mailwolt-update';
$fetchHelper = '/usr/local/sbin/mailwolt-fetch-tags';
@ -35,13 +38,63 @@ class CheckUpdates extends Command
$fetched = ($rc === 0);
}
// Direkter git fetch als Fallback (klappt wenn Credentials im Repo hinterlegt sind)
// Gitea/GitHub API funktioniert ohne Credentials wenn Repo öffentlich
if (!$fetched) {
$remoteUrl = trim((string) @shell_exec('git -C ' . escapeshellarg($appPath) . ' remote get-url origin 2>/dev/null'));
if (preg_match('~https?://([^/]+)/([^/]+/[^/]+?)(?:\.git)?$~', $remoteUrl, $rm)) {
$host = $rm[1];
$project = $rm[2];
// Gitea API
$apiUrl = "https://{$host}/api/v1/repos/{$project}/tags?limit=50";
$ctx = stream_context_create(['http' => ['timeout' => 5, 'ignore_errors' => true]]);
$json = @file_get_contents($apiUrl, false, $ctx);
if ($json) {
$tags = json_decode($json, true);
if (is_array($tags)) {
$versions = [];
foreach ($tags as $t) {
$name = $t['name'] ?? '';
if (preg_match('/^v[\d.]+$/', $name)) {
$versions[] = $name;
}
}
usort($versions, 'version_compare');
$latest = end($versions);
if ($latest) {
@mkdir(dirname($remoteFile), 0755, true);
file_put_contents($remoteFile, $latest);
$fetched = true;
}
}
}
}
}
// git ls-remote (klappt wenn Credentials im git-Config hinterlegt sind)
if (!$fetched) {
$lsOut = [];
@exec('git -C ' . escapeshellarg($appPath) . ' ls-remote --tags origin \'v*\' 2>/dev/null', $lsOut);
$lsVersions = [];
foreach ($lsOut as $line) {
if (preg_match('~refs/tags/(v[\d.]+)$~', $line, $m)) {
$lsVersions[] = $m[1];
}
}
if (!empty($lsVersions)) {
usort($lsVersions, 'version_compare');
$latest = end($lsVersions);
@mkdir(dirname($remoteFile), 0755, true);
file_put_contents($remoteFile, $latest);
$fetched = true;
}
}
// Direkter git fetch als letzter Fallback
if (!$fetched) {
@exec('git -C ' . escapeshellarg($appPath) . ' fetch --tags origin 2>/dev/null', $_, $rc);
}
// version_remote von Helfer geschrieben; als frisch wenn < 2h alt
$remoteFile = '/var/lib/mailwolt/version_remote';
$remoteRaw = '';
if (file_exists($remoteFile) && (time() - filemtime($remoteFile)) < 7200) {
$remoteRaw = trim((string) file_get_contents($remoteFile));

View File

@ -93,6 +93,11 @@ class UpdateCard extends Component
$this->recomputeUi();
}
public function openLogs(): void
{
$this->dispatch('openModal', component: 'ui.system.modal.update-modal');
}
public function refreshVersions(): void
{
if ($this->state === 'running') return;
@ -218,7 +223,7 @@ class UpdateCard extends Component
// Update-Checker schreibt:
// - updates:latest (normiert)
// - updates:latest_raw (original)
$latNorm = Cache::get('updates:latest');
$latNorm = $this->normalizeVersion(Cache::get('updates:latest') ?? '');
$latRaw = Cache::get('updates:latest_raw');
// Legacy-Fallback

View File

@ -169,7 +169,7 @@ class UpdatePage extends Component
{
$this->current = $this->readCurrentVersion();
$latNorm = Cache::get('updates:latest');
$latNorm = $this->normalizeVersion(Cache::get('updates:latest') ?? '');
$latRaw = Cache::get('updates:latest_raw');
if (!$latNorm && ($legacy = Cache::get('mailwolt.update_available'))) {

View File

@ -71,6 +71,14 @@
@endforeach
</select>
</div>
@script
<script>
try {
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
if (tz) $wire.set('timezone', tz);
} catch(e) {}
</script>
@endscript
</div>
{{-- ── Schritt 2: Domains ── --}}