Keep old pages readable, detect stale settings writes, make backups honest

- Own CSS is parsed on write only. A page whose stored CSS no longer
  passes a stricter rule answers 200 and opens in the editor; that one
  block loses its CSS. A document read several times in one request is
  validated once.
- Settings and theme refuse a write from an outdated form.
- A backup fails when a media file does not arrive completely and
  leaves no half directory behind; rotation counts intact backups only.
- The archive update takes its backup behind the maintenance page.
- A package import puts all media in place before removing the old
  ones, reports honestly when that fails and keeps a maintenance state
  that was already on.
- Restoring replaces the SQLite file in one move and points at pending
  migrations.
- Six irreversible actions ask first, in a dialog of the admin's own.
- Ctrl+S in the editor takes the field being typed in along; Delete
  no longer removes a block while a dialog is open.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Fable 5.2 committed 2026-11-10 11:41:05 +01:00
1 parent 0d61aa0f22
commit ead47cc924
25 files changed
+437 -72

No files matched your search

+15 -10
View File
@@ -195,16 +195,7 @@ final class ArchiveUpdate
return ['ok' => false, 'steps' => $schritte];
}
// Erst sichern, dann anfassen. Eine Sicherung nach dem Ersetzen wäre keine.
try {
$sicherung = $this->backup->create('vor dem Update');
$melden($schritte, 'Sicherung', true, sprintf('Datenbank und Medien liegen unter var/backups/%s.', (string) ($sicherung['name'] ?? 'sicherung')));
$this->phase('laden', sprintf('Fassung %s wird geladen …', $ziel));
} catch (\Throwable $fehler) {
$melden($schritte, 'Sicherung', false, 'Die Sicherung ist fehlgeschlagen: '.$fehler->getMessage().' Ohne sie wird nichts ersetzt.');
return ['ok' => false, 'steps' => $schritte];
}
$this->phase('laden', sprintf('Fassung %s wird geladen …', $ziel));
$archiv = $arbeit.'/kantsites-'.$ziel.'.zip';
// Direkt in die Datei, nicht erst als Zeichenkette in den Speicher: ein Archiv von einigen
@@ -250,6 +241,20 @@ final class ArchiveUpdate
$this->updater->maintenance(true);
$melden($schritte, 'Wartungszustand', true, 'Die Website antwortet währenddessen mit 503.');
// Erst sichern, dann anfassen - aber erst jetzt, hinter der Wartungsseite. Vorher entstand
// die Sicherung vor dem Laden und Entpacken: Was in diesen Sekunden bis Minuten noch
// hereinkam (eine Anfrage über ein Formular, ein gespeicherter Entwurf), fehlte in ihr und
// war nach einem Zurückschalten weg.
try {
$sicherung = $this->backup->create('vor dem Update');
$melden($schritte, 'Sicherung', true, sprintf('Datenbank und Medien liegen unter var/backups/%s.', (string) ($sicherung['name'] ?? 'sicherung')));
} catch (\Throwable $fehler) {
$this->updater->maintenance(false);
$melden($schritte, 'Sicherung', false, 'Die Sicherung ist fehlgeschlagen: '.$fehler->getMessage().' Ohne sie wird nichts ersetzt.');
return ['ok' => false, 'steps' => $schritte];
}
$alt = $arbeit.'/alt';
@mkdir($alt, 0o775, true);
$ersetzt = 0;