Initial commit: Pireon Admin — headless admin panel and public API
Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
138
app/Support/Maintenance.php
Normal file
138
app/Support/Maintenance.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Carbon\CarbonImmutable;
|
||||
|
||||
/**
|
||||
* Maintenance mode for the **public site only**.
|
||||
*
|
||||
* Deliberately not Laravel's `artisan down`, which would take this
|
||||
* application down too — including the panel. The whole point is that the
|
||||
* collective keeps working while visitors see a maintenance page: content can
|
||||
* still be edited, repositories still sync, and the team can preview the real
|
||||
* site through the usual bypasses.
|
||||
*
|
||||
* The flag lives in the database rather than in .env so an administrator can
|
||||
* flip it from the panel without a deploy.
|
||||
*/
|
||||
final class Maintenance
|
||||
{
|
||||
public const KEY = 'site.maintenance';
|
||||
|
||||
public static function isEnabled(): bool
|
||||
{
|
||||
$state = self::state();
|
||||
|
||||
if (! ($state['enabled'] ?? false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A window that has already passed lifts itself, so a forgotten flag
|
||||
// does not keep the site down indefinitely.
|
||||
if ($until = self::until()) {
|
||||
return ! $until->isPast();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string>|null $message Locale => message.
|
||||
*/
|
||||
public static function enable(?array $message = null, ?CarbonImmutable $until = null): void
|
||||
{
|
||||
Setting::set(self::KEY, [
|
||||
'enabled' => true,
|
||||
'message' => $message ?? self::state()['message'] ?? null,
|
||||
'until' => $until?->toIso8601String(),
|
||||
'started_at' => now()->toIso8601String(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function disable(): void
|
||||
{
|
||||
Setting::set(self::KEY, [
|
||||
...self::state(),
|
||||
'enabled' => false,
|
||||
'until' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The message shown to visitors, resolved to the request's language and
|
||||
* falling back to a translated default when none was written.
|
||||
*/
|
||||
public static function message(?string $locale = null): string
|
||||
{
|
||||
$locale ??= app()->getLocale();
|
||||
$messages = self::state()['message'] ?? [];
|
||||
|
||||
if (is_array($messages)) {
|
||||
$written = $messages[$locale]
|
||||
?? $messages[config('locales.fallback')]
|
||||
?? null;
|
||||
|
||||
if (filled($written)) {
|
||||
return (string) $written;
|
||||
}
|
||||
}
|
||||
|
||||
return __('maintenance.default_message');
|
||||
}
|
||||
|
||||
public static function until(): ?CarbonImmutable
|
||||
{
|
||||
$until = self::state()['until'] ?? null;
|
||||
|
||||
return filled($until) ? CarbonImmutable::parse($until) : null;
|
||||
}
|
||||
|
||||
public static function startedAt(): ?CarbonImmutable
|
||||
{
|
||||
$started = self::state()['started_at'] ?? null;
|
||||
|
||||
return filled($started) ? CarbonImmutable::parse($started) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seconds a caller should wait before retrying, for the `Retry-After`
|
||||
* header. Capped so a distant end date does not tell a CDN to stop asking
|
||||
* for a day.
|
||||
*/
|
||||
public static function retryAfter(): int
|
||||
{
|
||||
$until = self::until();
|
||||
|
||||
if ($until === null || $until->isPast()) {
|
||||
return 300;
|
||||
}
|
||||
|
||||
return min(3600, max(60, (int) now()->diffInSeconds($until)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Every locale's message, for editing in the panel.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function messages(): array
|
||||
{
|
||||
$messages = self::state()['message'] ?? [];
|
||||
|
||||
return is_array($messages) ? $messages : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function state(): array
|
||||
{
|
||||
$state = Setting::get(self::KEY, []);
|
||||
|
||||
return is_array($state) ? $state : [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user