Adds initial support for maintenance mode

main
Yasen Pramatarov 2025-09-24 20:27:17 +03:00
parent 315b68f928
commit 08953c6272
5 changed files with 152 additions and 1 deletions

View File

@ -0,0 +1,40 @@
<?php
namespace App\Core;
class Maintenance
{
public const FLAG_PATH = __DIR__ . '/../../storage/maintenance.flag';
public static function isEnabled(): bool
{
return file_exists(self::FLAG_PATH);
}
public static function enable(string $message = ''): bool
{
$dir = dirname(self::FLAG_PATH);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
$content = $message !== '' ? $message : 'Site is under maintenance';
return file_put_contents(self::FLAG_PATH, $content) !== false;
}
public static function disable(): bool
{
if (file_exists(self::FLAG_PATH)) {
return unlink(self::FLAG_PATH);
}
return true;
}
public static function getMessage(): string
{
if (!self::isEnabled()) {
return '';
}
$msg = @file_get_contents(self::FLAG_PATH);
return is_string($msg) ? trim($msg) : '';
}
}

View File

@ -0,0 +1,20 @@
<?php
/**
* Maintenance mode page
*/
?>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card border-warning">
<div class="card-header bg-warning text-dark">
<strong>Maintenance mode</strong>
</div>
<div class="card-body">
<p class="lead">The site is temporarily unavailable due to maintenance.</p>
<p class="text-muted">Please try again later.</p>
</div>
</div>
</div>
</div>
</div>

View File

@ -26,11 +26,29 @@ php scripts/migrate.php up
3. Typical deployment steps
- Pull new code from git.
- Put the site in maintenance mode (optional, recommended for sensitive changes).
- Put the site in maintenance mode (recommended): `php scripts/maintenance.php on "Upgrading database"`.
- Run `php scripts/migrate.php status`.
- If there are pending migrations, run `php scripts/migrate.php up`.
- Disable maintenance mode: `php scripts/maintenance.php off`.
- Clear opcache if applicable and resume traffic.
## Maintenance mode
Enable maintenance mode to temporarily block non-admin traffic during upgrades. Superusers (user ID 1 or with `superuser` right) can still access the site.
Commands:
```bash
# Turn on with optional message
php scripts/maintenance.php on "Upgrading database"
# Turn off
php scripts/maintenance.php off
# Status
php scripts/maintenance.php status
```
## Authoring new migrations
1. Create a new SQL file in `doc/database/migrations/`, e.g.:

View File

@ -229,6 +229,30 @@ if (!$pipeline->run()) {
exit;
}
// Maintenance mode: show maintenance page to non-superusers
try {
require_once __DIR__ . '/../app/core/Maintenance.php';
if (\App\Core\Maintenance::isEnabled()) {
$isSuperuser = false;
if ($validSession && isset($userId) && isset($userObject) && method_exists($userObject, 'hasRight')) {
// user 1 is always superuser per implementation, but also check explicit right
$isSuperuser = ($userId === 1) || (bool)$userObject->hasRight($userId, 'superuser');
}
if (!$isSuperuser) {
http_response_code(503);
// Show themed maintenance page
\App\Helpers\Theme::include('page-header');
\App\Helpers\Theme::include('page-menu');
include __DIR__ . '/../app/templates/maintenance.php';
\App\Helpers\Theme::include('page-footer');
ob_end_flush();
exit;
}
}
} catch (\Throwable $e) {
// Do not break app if maintenance check fails
}
// Apply per-user theme from DB into session (without persisting) once user is known
if ($validSession && isset($userId) && isset($userObject) && is_object($userObject) && method_exists($userObject, 'getUserTheme')) {
try {

View File

@ -0,0 +1,49 @@
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../app/core/Maintenance.php';
use App\Core\Maintenance;
function usage()
{
echo "\nJilo Web - Maintenance Mode\n";
echo "Usage:\n";
echo " php scripts/maintenance.php on [message] # Enable maintenance mode with optional message\n";
echo " php scripts/maintenance.php off # Disable maintenance mode\n";
echo " php scripts/maintenance.php status # Show maintenance status\n\n";
}
$cmd = $argv[1] ?? 'status';
try {
switch ($cmd) {
case 'on':
$message = $argv[2] ?? '';
if (Maintenance::enable($message)) {
echo "Maintenance mode ENABLED" . ($message ? ": $message" : '') . "\n";
exit(0);
}
fwrite(STDERR, "Failed to enable maintenance mode\n");
exit(1);
case 'off':
if (Maintenance::disable()) {
echo "Maintenance mode DISABLED\n";
exit(0);
}
fwrite(STDERR, "Failed to disable maintenance mode\n");
exit(1);
case 'status':
default:
if (Maintenance::isEnabled()) {
$msg = Maintenance::getMessage();
echo "Maintenance: ON" . ($msg ? " - $msg" : '') . "\n";
} else {
echo "Maintenance: OFF\n";
}
exit(0);
}
} catch (Throwable $e) {
fwrite(STDERR, "Error: " . $e->getMessage() . "\n");
exit(1);
}