feat: maintenance mode indicator for whitelisted ips

This commit is contained in:
2026-09-11 08:29:51 +02:00
parent 3cdaee1df3
commit d86eb1fd2e
5 changed files with 64 additions and 0 deletions
+1
View File
@@ -31,6 +31,7 @@ class AppExtension extends AbstractExtension
return [ return [
new TwigFunction('icon', [AppRuntime::class, 'renderIcon'], ['needs_environment' => true, 'is_safe' => ['html']]), new TwigFunction('icon', [AppRuntime::class, 'renderIcon'], ['needs_environment' => true, 'is_safe' => ['html']]),
new TwigFunction('is_current_route', [AppRuntime::class, 'isCurrentRoute']), new TwigFunction('is_current_route', [AppRuntime::class, 'isCurrentRoute']),
new TwigFunction('is_maintenance_mode', [AppRuntime::class, 'isMaintenanceMode']),
new TwigFunction('return_url', [AppRuntime::class, 'getEncodedReturnUrl']), new TwigFunction('return_url', [AppRuntime::class, 'getEncodedReturnUrl']),
new TwigFunction('forwarded_return_url', [AppRuntime::class, 'getForwardedReturnUrl']), new TwigFunction('forwarded_return_url', [AppRuntime::class, 'getForwardedReturnUrl']),
new TwigFunction('qa_attribute', [AppRuntime::class, 'renderQaAttribute'], ['is_safe' => ['html']]), new TwigFunction('qa_attribute', [AppRuntime::class, 'renderQaAttribute'], ['is_safe' => ['html']]),
+8
View File
@@ -180,6 +180,14 @@ class AppRuntime implements RuntimeExtensionInterface
return $requestedRoute === $route; return $requestedRoute === $route;
} }
/**
* The attribute is set by MaintenanceModeListener, on the ip whitelist branch only.
*/
public function isMaintenanceMode(): bool
{
return true === $this->requestStack->getMainRequest()?->attributes->get('_maintenance_mode_allowed');
}
public function getEncodedReturnUrl(): string public function getEncodedReturnUrl(): string
{ {
$masterRequest = $this->requestStack->getMainRequest(); $masterRequest = $this->requestStack->getMainRequest();
@@ -0,0 +1,6 @@
{% if is_maintenance_mode() %}
<div class="sticky top-0 z-50 bg-red-600 text-gray-100 px-4 lg:px-8 py-2 flex items-center justify-center space-x-2">
{{ icon('alert', 'w-5 h-5 flex-shrink-0') }}
<span class="leading-relaxed">Wartungsmodus — das Portal ist für andere Benutzer gesperrt.</span>
</div>
{% endif %}
+1
View File
@@ -16,6 +16,7 @@
{% endblock %} {% endblock %}
</head> </head>
<body class="bg-white text-gray-700 font-sans antialiased text-sm"> <body class="bg-white text-gray-700 font-sans antialiased text-sm">
{% include '_partials/_maintenance_banner.html.twig' %}
{% block body %}{% endblock %} {% block body %}{% endblock %}
{% include '_partials/_flashes.html.twig' %} {% include '_partials/_flashes.html.twig' %}
</body> </body>
+48
View File
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Tests\Twig;
use App\Twig\AppRuntime;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
class MaintenanceModeTest extends KernelTestCase
{
private RequestStack $requestStack;
private AppRuntime $appRuntime;
protected function setUp(): void
{
self::bootKernel();
$this->requestStack = self::getContainer()->get(RequestStack::class);
$this->appRuntime = self::getContainer()->get(AppRuntime::class);
}
public function testMaintenanceModeIsReportedWhenTheListenerMarkedTheRequest(): void
{
$request = Request::create('/administrative/assignment');
$request->attributes->set('_maintenance_mode_allowed', true);
$this->requestStack->push($request);
self::assertTrue($this->appRuntime->isMaintenanceMode());
}
public function testNoMaintenanceModeOnAnUnmarkedRequest(): void
{
$this->requestStack->push(Request::create('/administrative/assignment'));
self::assertFalse($this->appRuntime->isMaintenanceMode());
}
/**
* Rendering outside a request, an email or a console command, must not blow up.
*/
public function testNoMaintenanceModeWithoutARequest(): void
{
self::assertFalse($this->appRuntime->isMaintenanceMode());
}
}