feat: maintenance mode

This commit is contained in:
2026-09-08 12:38:43 +02:00
parent bc2af4d8e7
commit 7ed5bcd29a
4 changed files with 122 additions and 0 deletions
+5
View File
@@ -104,3 +104,8 @@ FEATURE_DATEV_EMAIL=false
FEATURE_MYEP_LOGIN=false FEATURE_MYEP_LOGIN=false
UPLOAD_REPLACEMENT_FILE=assets/pdf/chicken.pdf UPLOAD_REPLACEMENT_FILE=assets/pdf/chicken.pdf
MAINTENANCE_MODE_ENABLED=false
MAINTENANCE_MODE_IP_WHITELIST=188.245.62.21
MAINTENANCE_MODE_ROUTE_WHITELIST=
MAINTENANCE_MODE_PATH_WHITELIST=
+9
View File
@@ -1,3 +1,4 @@
# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json
parameters: parameters:
bpn_crm_id_admin: '%env(int:APP_BPN_CRM_ID_ADMIN)%' bpn_crm_id_admin: '%env(int:APP_BPN_CRM_ID_ADMIN)%'
bpn_crm_id_manager: '%env(int:APP_BPN_CRM_ID_MANAGER)%' bpn_crm_id_manager: '%env(int:APP_BPN_CRM_ID_MANAGER)%'
@@ -245,6 +246,14 @@ services:
$binGs: '%env(BIN_GS)%' $binGs: '%env(BIN_GS)%'
$binConvert: '%env(BIN_CONVERT)%' $binConvert: '%env(BIN_CONVERT)%'
App\EventListener\MaintenanceModeListener:
arguments:
$options:
enabled: '%env(bool:MAINTENANCE_MODE_ENABLED)%'
whitelisted_ips: '%env(csv:MAINTENANCE_MODE_IP_WHITELIST)%'
whitelisted_routes: '%env(csv:MAINTENANCE_MODE_ROUTE_WHITELIST)%'
whitelisted_paths: '%env(csv:MAINTENANCE_MODE_PATH_WHITELIST)%'
App\EventListener\UploadSessionListener: App\EventListener\UploadSessionListener:
tags: tags:
- name: kernel.event_listener - name: kernel.event_listener
@@ -0,0 +1,86 @@
<?php
namespace App\EventListener;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\IpUtils;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Twig\Environment;
#[AsEventListener(event: KernelEvents::REQUEST, method: 'onKernelRequest')]
class MaintenanceModeListener
{
/**
* @var array<string, mixed>
*/
private array $config;
/**
* @param array<string, mixed> $options
*/
public function __construct(private readonly Environment $twig, array $options)
{
$this->config = $this->resolveConfig($options);
}
public function onKernelRequest(RequestEvent $event): void
{
if (false === $event->isMainRequest()) {
return;
}
if (false === $this->config['enabled']) {
return;
}
$request = $event->getRequest();
// Check requested path against whitelist
foreach ($this->config['whitelisted_paths'] as $whitelistedPath) {
$prefix = rtrim((string) $whitelistedPath, '/');
if ($request->getPathInfo() === $prefix || str_starts_with($request->getPathInfo(), $prefix.'/')) {
return;
}
}
// Check user's IP against whitelist
if (true === IpUtils::checkIp($request->getClientIp(), $this->config['whitelisted_ips'])) {
$request->attributes->set('_maintenance_mode_allowed', true);
return;
}
// Check requested route against whitelist
if (true === in_array($request->attributes->get('_route'), $this->config['whitelisted_routes'])) {
return;
}
$content = $this->twig->render('maintenance/index.html.twig');
$event->setResponse(new Response($content, Response::HTTP_SERVICE_UNAVAILABLE));
}
/**
* @param array<string, mixed> $options
*
* @return array<string, mixed>
*/
private function resolveConfig(array $options): array
{
$optionsResolver = new OptionsResolver();
$optionsResolver
->setDefaults([
'enabled' => false,
'whitelisted_ips' => [],
'whitelisted_routes' => [],
'whitelisted_paths' => [],
])
;
return $optionsResolver->resolve($options);
}
}
+22
View File
@@ -0,0 +1,22 @@
{% extends 'base.html.twig' %}
{% block body %}
<div class="w-full h-screen flex flex-col items-center justify-center px-4">
<div class="w-full max-w-md p-8 bg-gray-100 border border-gray-200 rounded-md">
<h1 class="flex items-center justify-between mb-6">
<img class="h-10 w-auto" src="{{ asset('build/images/logo.svg') }}" alt="My E&amp;P Team">
<span class="text-3xl md:text-4xl leading-none font-bold text-gray-900">MyE&amp;P Team</span>
</h1>
<h2 class="text-2xl font-bold mb-8">
...ist außer Betrieb
</h2>
<p class="mb-8">
Wir müssen gerade leider unaufschiebbare Wartungsarbeiten durchführen, sind aber schnellstmöglich wieder
online. Versprochen.
</p>
<p>
Vielen Dank für Dein Verständnis!
</p>
</div>
</div>
{% endblock %}