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:
1 parent
0d61aa0f22
commit
ead47cc924
25 files changed
+437
-72
No files matched your search
@@ -9,6 +9,9 @@ final class DocumentValidator
|
||||
{
|
||||
private bool $writing = false;
|
||||
|
||||
/** @var array<string, true> beim Lesen bereits geprüfte Dokumente dieser Anfrage */
|
||||
private array $passed = [];
|
||||
|
||||
public function __construct(private StyleCompiler $styles = new StyleCompiler(), private CustomCode $code = new CustomCode(), private ?PluginRegistry $plugins = null)
|
||||
{
|
||||
}
|
||||
@@ -59,6 +62,24 @@ final class DocumentValidator
|
||||
* lässt unpassende Eigenschaften ohnehin nicht durch.
|
||||
*/
|
||||
public function validate(array $document, bool $requireHeading = true, bool $writing = false): void
|
||||
{
|
||||
// Beim Lesen wird dasselbe Dokument in einer Anfrage oft mehrfach geholt (Seite,
|
||||
// Brotkrumen, strukturierte Daten). Geprüft wird es einmal; der Schlüssel ist sein Inhalt,
|
||||
// ein geändertes Dokument ist also ein anderes.
|
||||
$seen = null;
|
||||
if (!$writing) {
|
||||
$seen = hash('xxh128', serialize($document)).($requireHeading ? '1' : '0');
|
||||
if (isset($this->passed[$seen])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->check($document, $requireHeading, $writing);
|
||||
if (null !== $seen) {
|
||||
$this->passed[$seen] = true;
|
||||
}
|
||||
}
|
||||
|
||||
private function check(array $document, bool $requireHeading, bool $writing): void
|
||||
{
|
||||
$this->writing = $writing;
|
||||
$schemaVersion = $document['schemaVersion'] ?? null;
|
||||
@@ -133,7 +154,7 @@ final class DocumentValidator
|
||||
$this->require(is_string($key) && strlen($key) <= 110 && is_string($hash) && 1 === preg_match('/^[a-f0-9]{8}$/D', $hash), 'Ungültiger Vermerk zur Übersetzung.');
|
||||
}
|
||||
try {
|
||||
$this->validate(Translations::apply($document, $locale), $requireHeading, $this->writing);
|
||||
$this->check(Translations::apply($document, $locale), $requireHeading, $this->writing);
|
||||
} catch (InvalidDocument $error) {
|
||||
throw new InvalidDocument(sprintf('%s (%s): %s', Languages::CATALOG[$locale]['name'], $locale, $error->getMessage()), previous: $error);
|
||||
}
|
||||
@@ -171,7 +192,17 @@ final class DocumentValidator
|
||||
// and is answered in the controller, not here.
|
||||
$this->require(CustomCode::supports($schemaVersion), 'Own code requires schema v13.');
|
||||
$this->require(is_string($block[$own]), sprintf('"%s" must be text.', $own));
|
||||
'css' === $own ? $this->code->checkCss($block[$own]) : $this->code->checkScript($block[$own]);
|
||||
// Eigenes CSS wird nur beim Schreiben geparst. Was gespeichert ist, galt beim Speichern;
|
||||
// ist eine Regel inzwischen strenger, lässt compileCss() das CSS dieses einen Blocks
|
||||
// weg (ADR 116). Hier beim Lesen zu werfen hieße: die Seite antwortet mit 500 und lässt
|
||||
// sich nicht einmal mehr zum Reparieren öffnen.
|
||||
if ('css' === $own) {
|
||||
if ($this->writing) {
|
||||
$this->code->checkCss($block[$own]);
|
||||
}
|
||||
} else {
|
||||
$this->code->checkScript($block[$own]);
|
||||
}
|
||||
}
|
||||
if (isset($block['style'])) {
|
||||
// Free styling: any property of StyleSchema, per device, with an optional hover value.
|
||||
|
||||
Reference in new issue
Block a user