Fix lost form submissions on archives, the unlocked update finish and six more

Update Symfony to 7.4.23 (12 advisories in 8 packages).

- A form can be sent from /beitraege, /kategorie/... and /schlagwort/...;
  it answered 404 before anything was stored or mailed.
- Booleans reach the database as integers, so MySQL in strict mode
  accepts form submissions, task switches and plugin states.
- A stepped form with a required multiple choice shows its message
  instead of stopping on a TypeError.
- The second update step runs under the update lock; a concurrent
  finish no longer rolls a successful update back.
- Accordion entries and gallery images can be selected from the
  editor panel again.
- Category and tag names are escaped in the archive heading.
- Restoring a published page from the bin needs the publisher role.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Fable 5.2 committed 2026-11-10 11:15:49 +01:00
1 parent 441e629e80
commit d464c82ac8
17 files changed
+324 -168

No files matched your search

+33
View File
@@ -163,6 +163,39 @@ final class BacklogTest extends TestCase
self::assertStringContainsString('Dieses Feld wird benötigt.', $antwort->getContent());
}
public function testAFormInTheFooterCanBeSentFromAnArchive(): void
{
(new FormRepository($this->db))->save('kontakt', 'Kontakt', [
['name' => 'email', 'type' => 'email', 'label' => 'E-Mail', 'required' => true],
['name' => 'datenschutz', 'type' => 'consent', 'label' => 'Einverstanden'],
], ['recipient' => 'info@example.org'], 0);
$footer = $this->partials->findByKind('footer');
$doc = $footer['document'];
$doc['schemaVersion'] = 23;
$doc['blocks'][] = ['id' => 'fuss-formular', 'type' => 'form', 'props' => ['form' => 'kontakt']];
$this->partials->save($footer['id'], $doc, $footer['version']);
$this->publishHome(DemoContent::starter('Start'));
$this->post('erster', 'Erster Beitrag', '2026-01-01 10:00', ['Neues']);
self::assertStringContainsString('name="page" value="beitraege"', $this->request('/beitraege')->getContent());
// Ein Archiv ist keine gespeicherte Seite. Vorher endete das Absenden hier in einer 404,
// bevor irgendetwas gespeichert oder verschickt war.
$body = fn (string $page, string $email): array => ['page' => $page, 'block' => 'fuss-formular', 'issued' => (string) (time() - 10), 'issuedSignature' => FormRepository::stamp('kontakt', time() - 10, 'test-only'), 'email' => $email, 'datenschutz' => 'ja'];
$fehler = $this->request('/formular/kontakt', 'POST', $body('beitraege', ''));
self::assertSame(422, $fehler->getStatusCode());
self::assertStringContainsString('Dieses Feld wird benötigt.', $fehler->getContent());
self::assertStringContainsString('Erster Beitrag', $fehler->getContent(), 'Die Meldung steht im Archiv, nicht auf einer Fehlerseite.');
foreach (['beitraege', 'kategorie/neues'] as $n => $archiv) {
$antwort = $this->request('/formular/kontakt', 'POST', $body($archiv, 'kunde'.$n.'@example.org'));
self::assertSame(303, $antwort->getStatusCode());
self::assertSame('/'.$archiv.'?gesendet=kontakt#fuss-formular', $antwort->headers->get('Location'));
self::assertSame($n + 1, (int) $this->db->fetchOne('SELECT COUNT(*) FROM form_submission'), 'Die Anfrage ist gespeichert.');
}
self::assertSame(200, $this->request('/beitraege?gesendet=kontakt')->getStatusCode());
self::assertSame(404, $this->request('/formular/kontakt', 'POST', $body('gibt-es-nicht', 'x@example.org'))->getStatusCode(), 'Eine unbekannte Seite bleibt eine unbekannte Seite.');
}
public function testASectionLinkedTwiceRendersWithoutDuplicateIds(): void
{
$sektion = DemoContent::starter('Band');