```
✨ feat(maintenance): Ajoute une page et un mode maintenance activable.
```
This commit is contained in:
1
.env
1
.env
@@ -98,3 +98,4 @@ STRIPE_SECRET_KEY=sk_test_***
|
||||
###< stripe/stripe-php ###
|
||||
INTRANET_LOCK=true
|
||||
TVA_ENABLED=false
|
||||
MAINTENANCE_ENABLED=false
|
||||
|
||||
@@ -1,29 +1,8 @@
|
||||
# Nom du workflow
|
||||
name: Symfony CI - Install, Test, Build, Attest & Deploy
|
||||
|
||||
# Déclencheurs du workflow
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master # Ou 'main'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches:
|
||||
- master # Ou 'main'
|
||||
|
||||
# Permissions nécessaires pour les actions utilisées
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
security-events: write # Requis pour Snyk pour poster les résultats
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: 🚀 Deploy to Production
|
||||
runs-on: ubuntu-latest # N'oublie pas de préciser l'OS du runner
|
||||
steps:
|
||||
- name: Deploy with SSH & Ansible
|
||||
- name: Deploy with SSH
|
||||
uses: appleboy/ssh-action@v1.0.0
|
||||
with:
|
||||
host: ${{ secrets.SSH_HOST }}
|
||||
@@ -31,4 +10,16 @@ jobs:
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
port: 22
|
||||
script: |
|
||||
cd /var/www/ludikevent-intranet && git pull && nohup sh ./update.sh
|
||||
cd /var/www/ludikevent-intranet
|
||||
|
||||
# 1. Activer la maintenance
|
||||
php bin/console app:maintenance on
|
||||
|
||||
# 2. Mise à jour du code
|
||||
git pull
|
||||
|
||||
# 3. Exécuter ton script d'update (migrations, install, etc.)
|
||||
sh ./update.sh
|
||||
|
||||
# 4. Désactiver la maintenance
|
||||
php bin/console app:maintenance off
|
||||
|
||||
@@ -24,3 +24,8 @@ services:
|
||||
# Utilisation du listener de Nelmio (identifiant officiel)
|
||||
$cspListener: '@nelmio_security.csp_listener'
|
||||
|
||||
App\Security\MaintenanceListener:
|
||||
arguments:
|
||||
$isMaintenance: '%env(MAINTENANCE_ENABLED)%'
|
||||
tags:
|
||||
- { name: kernel.event_listener, event: kernel.request, priority: 255 }
|
||||
|
||||
59
src/Command/MaintenanceCommand.php
Normal file
59
src/Command/MaintenanceCommand.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'app:maintenance',
|
||||
description: 'Active ou désactive le mode maintenance',
|
||||
)]
|
||||
class MaintenanceCommand extends Command
|
||||
{
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->addArgument('status', InputArgument::REQUIRED, 'on ou off');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$status = $input->getArgument('status');
|
||||
$envFile = dirname(__DIR__, 2) . '/.env.local';
|
||||
|
||||
// Si .env.local n'existe pas, on prend le .env
|
||||
if (!file_exists($envFile)) {
|
||||
$envFile = dirname(__DIR__, 2) . '/.env';
|
||||
}
|
||||
|
||||
$content = file_get_contents($envFile);
|
||||
$value = ($status === 'on') ? 'true' : 'false';
|
||||
|
||||
// On remplace la valeur de la variable
|
||||
if (preg_match('/MAINTENANCE_ENABLED=/', $content)) {
|
||||
$content = preg_replace('/MAINTENANCE_ENABLED=(true|false)/', "MAINTENANCE_ENABLED=$value", $content);
|
||||
} else {
|
||||
$content .= "\nMAINTENANCE_ENABLED=$value";
|
||||
}
|
||||
|
||||
file_put_contents($envFile, $content);
|
||||
|
||||
// Vider le cache pour appliquer le changement
|
||||
$io->note("Mise à jour du fichier .env et nettoyage du cache...");
|
||||
passthru('php bin/console cache:clear');
|
||||
|
||||
if ($status === 'on') {
|
||||
$io->success('Mode maintenance ACTIVÉ ⚙️ (Le site est caché au public)');
|
||||
} else {
|
||||
$io->success('Mode maintenance DÉSACTIVÉ ✅ (Le site est en ligne)');
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,8 @@ class IntranetLocked
|
||||
|
||||
public function onControl(RequestEvent $requestEvent): void
|
||||
{
|
||||
|
||||
|
||||
// On ignore également le contrôle des services pour l'IP whitelisted
|
||||
if ($this->isWhitelisted($requestEvent) || $this->isDebugRoute($requestEvent)) {
|
||||
return;
|
||||
|
||||
40
src/Security/MaintenanceListener.php
Normal file
40
src/Security/MaintenanceListener.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Twig\Environment;
|
||||
|
||||
class MaintenanceListener
|
||||
{
|
||||
private $twig;
|
||||
private $isMaintenance;
|
||||
private $ipsWhiteList;
|
||||
|
||||
public function __construct(Environment $twig, string $isMaintenance)
|
||||
{
|
||||
$this->twig = $twig;
|
||||
$this->isMaintenance = filter_var($isMaintenance, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
|
||||
public function onKernelRequest(RequestEvent $event)
|
||||
{
|
||||
// On n'active la maintenance que sur la requête principale (pas les sous-requêtes)
|
||||
if (!$event->isMainRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Si la maintenance est désactivée, on ne fait rien
|
||||
if (!$this->isMaintenance) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Si l'IP du visiteur est dans la whitelist, on le laisse passer
|
||||
// On affiche la page de maintenance
|
||||
$content = $this->twig->render('security/maintenance.twig');
|
||||
|
||||
// On renvoie une réponse 503 (Service Unavailable)
|
||||
$event->setResponse(new Response($content, 503));
|
||||
}
|
||||
}
|
||||
65
templates/security/maintenance.twig
Normal file
65
templates/security/maintenance.twig
Normal file
@@ -0,0 +1,65 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Maintenance en cours - Ludik Event</title>
|
||||
{{ vite_asset('reserve.js') }}
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&display=swap');
|
||||
body { font-family: 'Inter', sans-serif; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-slate-50 min-h-screen flex items-center justify-center p-6">
|
||||
|
||||
<div class="max-w-3xl w-full text-center">
|
||||
|
||||
{# --- BADGE --- #}
|
||||
<div class="inline-block bg-amber-100 text-amber-600 px-4 py-1.5 rounded-full text-[10px] font-black uppercase tracking-widest mb-8 animate-pulse">
|
||||
Mise à jour en cours ⚙️
|
||||
</div>
|
||||
|
||||
{# --- TITRE IMPACTANT --- #}
|
||||
<h1 class="text-6xl md:text-8xl font-black text-slate-900 uppercase italic tracking-tighter leading-[0.85] mb-8">
|
||||
ON GONFLE <br><span class="text-blue-600">LE SITE !</span>
|
||||
</h1>
|
||||
|
||||
{# --- MESSAGE --- #}
|
||||
<div class="bg-white p-8 md:p-12 rounded-[3rem] shadow-xl border border-slate-100 relative overflow-hidden">
|
||||
<p class="text-xl text-slate-600 font-medium italic leading-relaxed relative z-10">
|
||||
On installe de nouvelles fonctionnalités pour rendre vos réservations encore plus ludiques.
|
||||
<strong>On revient dans quelques minutes.</strong>
|
||||
</p>
|
||||
|
||||
{# Décoration de fond (forme abstraite) #}
|
||||
<div class="absolute -right-10 -bottom-10 w-40 h-40 bg-blue-50 rounded-full blur-3xl opacity-50"></div>
|
||||
</div>
|
||||
|
||||
{# --- CONTACT D'URGENCE --- #}
|
||||
<div class="mt-12 flex flex-col md:flex-row items-center justify-center gap-6">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1 text-center md:text-left">Besoin d'aide ?</span>
|
||||
<a href="tel:0614172447" class="text-2xl font-black text-slate-900 italic hover:text-blue-600 transition-colors">
|
||||
06 14 17 24 47
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="hidden md:block w-[1px] h-10 bg-slate-200"></div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<span class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1 text-center md:text-left">Par écrit</span>
|
||||
<a href="mailto:lilian@ludikevent.fr" class="text-2xl font-black text-slate-900 italic hover:text-blue-600 transition-colors">
|
||||
lilian@ludikevent.fr
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# --- FOOTER --- #}
|
||||
<p class="mt-16 text-[10px] font-black text-slate-300 uppercase tracking-[0.4em]">
|
||||
Ludik Event © {{ "now"|date("Y") }} - Hauts-de-France
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user