184 lines
8.1 KiB
PHP
184 lines
8.1 KiB
PHP
<?php
|
||
|
||
namespace App\Controller;
|
||
|
||
use App\Content\Consent;
|
||
use App\Content\DemoContent;
|
||
use App\Content\MediaLibrary;
|
||
use App\Content\NotFoundPage;
|
||
use App\Content\PageRepository;
|
||
use App\Content\RedirectRepository;
|
||
use App\Content\SiteSettings;
|
||
use App\Content\Theme;
|
||
use App\Domain\InvalidPage;
|
||
use App\Domain\StaleWrite;
|
||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||
use Symfony\Component\HttpFoundation\Request;
|
||
use Symfony\Component\HttpFoundation\Response;
|
||
use Symfony\Component\Routing\Attribute\Route;
|
||
|
||
final class SettingsController extends AbstractController
|
||
{
|
||
public function __construct(private SiteSettings $settings, private RedirectRepository $redirects, private PageRepository $pages, private MediaLibrary $media, private Theme $theme, private NotFoundPage $notFoundPage)
|
||
{
|
||
}
|
||
|
||
#[Route('/%kant.admin_path%/settings', name: 'admin_settings', methods: ['GET'])]
|
||
public function index(Request $request): Response
|
||
{
|
||
$choosable = [];
|
||
foreach ($this->pages->listForEditor() as $page) {
|
||
// Only a published page can serve as the root; a draft would answer every visit with 404.
|
||
if ('page' === $page['type'] && null !== $page['published_revision_id']) {
|
||
$document = json_decode($page['document'] ?? '{}', true, 512, JSON_THROW_ON_ERROR);
|
||
$choosable[] = ['path' => $page['path'], 'title' => $document['title'] ?? $page['path']];
|
||
}
|
||
}
|
||
|
||
return $this->render('admin/settings.html.twig', [
|
||
'settings' => $this->settings->load(),
|
||
'notFoundSelection' => $this->notFoundPage->selected(),
|
||
'redirects' => $this->redirects->all($request->query->getInt('seite', 1)),
|
||
'choosableHome' => $choosable,
|
||
'consentGroups' => Consent::GROUPS,
|
||
'missingLegal' => $this->settings->missingLegalPages(),
|
||
'consentGroupHelp' => Consent::GROUP_HELP,
|
||
// Für das Symbol der Website: die Mediathek zur Auswahl, die neuesten zuerst.
|
||
'images' => $this->media->page(1, false, 96)['items'],
|
||
// Fuer die Farbfelder: dieselbe Palette, die auch der Editor anbietet.
|
||
'palette' => $this->theme->load()['colors'],
|
||
]);
|
||
}
|
||
|
||
#[Route('/%kant.admin_path%/settings/company', name: 'admin_settings_save', methods: ['POST'])]
|
||
public function save(Request $request): Response
|
||
{
|
||
$this->denyAccessUnlessGranted('ROLE_EDITOR');
|
||
if (!$this->isCsrfTokenValid('settings', $request->request->getString('_csrf_token'))) {
|
||
return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
|
||
}
|
||
try {
|
||
$this->settings->save($request->request->all());
|
||
} catch (InvalidPage $e) {
|
||
return $this->back($e->getMessage());
|
||
}
|
||
|
||
return $this->back('Die Unternehmensdaten wurden gespeichert.', 'success');
|
||
}
|
||
|
||
#[Route('/%kant.admin_path%/settings/not-found', name: 'admin_not_found_save', methods: ['POST'])]
|
||
public function saveNotFound(Request $request): Response
|
||
{
|
||
$this->denyAccessUnlessGranted('ROLE_PUBLISHER');
|
||
if (!$this->isCsrfTokenValid('settings', $request->request->getString('_csrf_token'))) {
|
||
return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
|
||
}
|
||
try {
|
||
$expectedId = $request->request->getString('expectedId');
|
||
if ('create' === $request->request->getString('action')) {
|
||
$id = $this->notFoundPage->create($expectedId);
|
||
$this->addFlash('success', 'Die 404-Vorlage wurde als Entwurf angelegt und zugewiesen. Nach dem Veröffentlichen ersetzt sie die Standard-404.');
|
||
|
||
return $this->redirectToRoute('admin_editor', ['id' => $id]);
|
||
}
|
||
$id = $request->request->getString('notFoundPageId');
|
||
$this->settings->assignNotFoundPage($id, $expectedId);
|
||
$selection = $this->notFoundPage->selected();
|
||
$message = '' === $id ? 'Die Standard-404 im Website-Design ist wieder aktiv.'
|
||
: ($selection['published'] ? 'Die 404-Seite wurde zugewiesen.' : 'Die Seite wurde zugewiesen. Bis zu ihrer Veröffentlichung erscheint die Standard-404.');
|
||
$this->addFlash('success', $message);
|
||
} catch (InvalidPage|StaleWrite $error) {
|
||
$this->addFlash('error', $error->getMessage());
|
||
}
|
||
|
||
return $this->redirectToRoute('admin_settings', ['_fragment' => 'not-found']);
|
||
}
|
||
|
||
#[Route('/%kant.admin_path%/settings/redirects', name: 'admin_redirect_save', methods: ['POST'])]
|
||
public function saveRedirect(Request $request): Response
|
||
{
|
||
$this->denyAccessUnlessGranted('ROLE_EDITOR');
|
||
if (!$this->isCsrfTokenValid('settings', $request->request->getString('_csrf_token'))) {
|
||
return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
|
||
}
|
||
$remove = $request->request->getString('remove');
|
||
if ('' !== $remove) {
|
||
$this->redirects->delete($remove);
|
||
|
||
return $this->back('Die Weiterleitung wurde entfernt.', 'success');
|
||
}
|
||
try {
|
||
$this->redirects->save(
|
||
$request->request->getString('from'),
|
||
$request->request->getString('to'),
|
||
$request->request->getInt('status', 301),
|
||
);
|
||
} catch (InvalidPage $e) {
|
||
return $this->back($e->getMessage());
|
||
}
|
||
|
||
return $this->back('Die Weiterleitung wurde gespeichert.', 'success');
|
||
}
|
||
|
||
/**
|
||
* Creates the privacy statement and the imprint, with a skeleton whose gaps are marked.
|
||
*
|
||
* The pages are mandatory, the text is not something a CMS can write: what gets created is the
|
||
* structure with every required item named and marked as still to be filled in.
|
||
*/
|
||
#[Route('/%kant.admin_path%/settings/rechtliches', name: 'admin_legal_pages', methods: ['POST'])]
|
||
public function legalPages(Request $request): Response
|
||
{
|
||
$this->denyAccessUnlessGranted('ROLE_EDITOR');
|
||
if (!$this->isCsrfTokenValid('settings', $request->request->getString('_csrf_token'))) {
|
||
return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
|
||
}
|
||
$settings = $this->settings->load();
|
||
$created = [];
|
||
try {
|
||
foreach (DemoContent::LEGAL as $slug => $label) {
|
||
$key = 'datenschutz' === $slug ? 'privacyPath' : 'imprintPath';
|
||
// An existing page is never overwritten - it may already carry the real text.
|
||
$existing = null !== $this->pages->findPublished($slug) || $this->pageExists($slug);
|
||
if (!$existing) {
|
||
$id = $this->pages->createPage($slug, null, 'page', DemoContent::legalPage($slug));
|
||
$page = $this->pages->findForEditor($id);
|
||
$this->pages->publish($id, $page['draft_revision_id'], $page['version']);
|
||
$created[] = $label;
|
||
}
|
||
$settings[$key] = $slug;
|
||
}
|
||
$this->settings->save([...$settings, 'consentGroups' => $settings['consentGroups'], 'sameAs' => implode('
|
||
', $settings['sameAs'])]);
|
||
} catch (InvalidPage $e) {
|
||
return $this->back($e->getMessage());
|
||
}
|
||
|
||
return $this->back(
|
||
[] === $created
|
||
? 'Die Seiten waren schon vorhanden und sind jetzt verknüpft. Der Inhalt bleibt unverändert.'
|
||
: sprintf('%s angelegt und verknüpft. Beide Seiten sind veröffentlicht und müssen noch ausgefüllt werden – die Pflichtangaben sind darin markiert.', implode(' und ', $created)),
|
||
'success',
|
||
);
|
||
}
|
||
|
||
/** Also finds a page that exists but is not published yet. */
|
||
private function pageExists(string $path): bool
|
||
{
|
||
foreach ($this->pages->listForEditor() as $page) {
|
||
if ($path === $page['path']) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
private function back(string $message, string $type = 'error'): Response
|
||
{
|
||
$this->addFlash($type, $message);
|
||
|
||
return $this->redirectToRoute('admin_settings');
|
||
}
|
||
}
|