implementing maintenance mode

This commit is contained in:
Ferdinand Kuhl 2024-11-28 17:05:22 +01:00
parent 2f1fe72441
commit 831b715608
12 changed files with 236 additions and 0 deletions

View file

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace DigiComp\FlowMaintenanceMode\AllowModules;
use Psr\Http\Message\ServerRequestInterface;
interface AllowModuleInterface
{
public function isRequestAllowed(ServerRequestInterface $request): bool;
}

View file

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace DigiComp\FlowMaintenanceMode\AllowModules;
use Psr\Http\Message\ServerRequestInterface;
class ByCookieAllowModule implements AllowModuleInterface
{
protected ?string $cookieName;
protected ?string $cookieValue;
/**
* @param string|null $cookieName
* @param string|null $cookieValue
*/
public function __construct(?string $cookieName, ?string $cookieValue)
{
$this->cookieName = $cookieName;
$this->cookieValue = $cookieValue;
}
public function isRequestAllowed(ServerRequestInterface $request): bool
{
$cookies = $request->getCookieParams();
if ($this->cookieName === null || !isset($cookies[$this->cookieName])) {
return false;
}
if ($this->cookieValue !== null && $cookies[$this->cookieName] !== $this->cookieValue) {
return false;
}
return true;
}
}

9
Classes/Exception.php Normal file
View file

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace DigiComp\FlowMaintenanceMode;
class Exception extends \Neos\Flow\Exception
{
}

View file

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace DigiComp\FlowMaintenanceMode\Http;
use DigiComp\FlowMaintenanceMode\AllowModules\AllowModuleInterface;
use DigiComp\FlowMaintenanceMode\MaintenanceModeActiveException;
use DigiComp\FlowMaintenanceMode\MaintenanceModeManagerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class MaintenanceModeMiddleware implements MiddlewareInterface
{
protected MaintenanceModeManagerInterface $maintenanceModeManager;
/**
* @var array<array-key, AllowModuleInterface>
*/
protected array $allowModules;
public function __construct(
MaintenanceModeManagerInterface $maintenanceModeManager,
AllowModuleInterface ...$allowModules
) {
$this->maintenanceModeManager = $maintenanceModeManager;
$this->allowModules = $allowModules;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if ($this->maintenanceModeManager->isMaintenanceMode()) {
foreach ($this->allowModules as $allowModule) {
if ($allowModule->isRequestAllowed($request)) {
return $handler->handle($request);
}
}
throw new MaintenanceModeActiveException('Maintenance is active');
}
return $handler->handle($request);
}
}

View file

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace DigiComp\FlowMaintenanceMode\Http;
use DigiComp\FlowMaintenanceMode\MaintenanceModeManagerInterface;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\ObjectManagement\ObjectManagerInterface;
use Neos\Utility\PositionalArraySorter;
class MaintenanceModeMiddlewareFactory
{
protected ObjectManagerInterface $objectManager;
#[Flow\InjectConfiguration(path: 'allowModules')]
protected array $allowModuleNames;
/**
* @param ObjectManagerInterface $objectManager
*/
public function __construct(ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
public function create(): MaintenanceModeMiddleware
{
$allowModules = [];
$sorter = new PositionalArraySorter($this->allowModuleNames);
foreach ($sorter->getSortedKeys() as $moduleName) {
$allowModules[] = $this->objectManager->get($moduleName);
}
return new MaintenanceModeMiddleware(
$this->objectManager->get(MaintenanceModeManagerInterface::class),
...$allowModules
);
}
}

View file

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace DigiComp\FlowMaintenanceMode;
class MaintenanceModeActiveException extends Exception
{
protected $statusCode = 503;
}

View file

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace DigiComp\FlowMaintenanceMode;
class MaintenanceModeDistributionFileManager implements MaintenanceModeManagerInterface
{
public function isMaintenanceMode(): bool
{
if (\file_exists(\FLOW_PATH_ROOT . '/.maintenance')) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace DigiComp\FlowMaintenanceMode;
interface MaintenanceModeManagerInterface
{
public function isMaintenanceMode(): bool;
}

View file

@ -0,0 +1,11 @@
DigiComp.FlowMaintenance:AllowByCookieModule:
className: DigiComp\FlowMaintenanceMode\AllowModules\ByCookieAllowModule
arguments:
1:
setting: DigiComp.FlowMaintenanceMode.allowCookie.name
2:
setting: DigiComp.FlowMaintenanceMode.allowCookie.value
DigiComp.FlowMaintenance:MaintenanceModeMiddleware:
className: DigiComp\FlowMaintenanceMode\Http\MaintenanceModeMiddleware
factoryObjectName: DigiComp\FlowMaintenanceMode\Http\MaintenanceModeMiddlewareFactory

View file

@ -0,0 +1,20 @@
Neos:
Flow:
http:
middlewares:
maintenanceMode:
position: "after trustedProxies"
middleware: "DigiComp.FlowMaintenance:MaintenanceModeMiddleware"
error:
exceptionHandler:
renderingGroups:
maintenanceErrors:
matchingStatusCodes:
- 503
options:
error:
options:
logException: false
templatePathAndFilename: "resource://Neos.Flow/Private/Templates/Error/Default.html"
variables:
errorDescription: "The system is currently under maintenance. Try again later."

View file

@ -0,0 +1,8 @@
DigiComp:
FlowMaintenanceMode:
allowCookie:
name: ~
value: ~
allowModules:
DigiComp.FlowMaintenance:AllowByCookieModule:
position: start

21
composer.json Normal file
View file

@ -0,0 +1,21 @@
{
"name": "digicomp/flow-maintenance-mode",
"description": "Maintenance mode for Flow based systems",
"type": "neos-package",
"require": {
"neos/flow": "^7.3",
"php": "^8.1"
},
"autoload": {
"psr-4": {
"DigiComp\\FlowMaintenanceMode\\": "Classes"
}
},
"extra": {
"neos": {
"package-key": "DigiComp.FlowMaintenanceMode"
},
"applied-flow-migrations": [
]
}
}