feat: Provisionner automatiquement un nouvel établissement
Some checks failed
CI / Naming Conventions (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Build Check (push) Has been cancelled

Lorsqu'un super-admin crée un établissement via l'interface, le système
doit automatiquement créer la base tenant, exécuter les migrations,
créer le premier utilisateur admin et envoyer l'invitation — le tout
de manière asynchrone pour ne pas bloquer la réponse HTTP.

Ce mécanisme rend chaque établissement opérationnel dès sa création
sans intervention manuelle sur l'infrastructure.
This commit is contained in:
2026-04-08 13:55:41 +02:00
parent bec211ebf0
commit 713e408773
65 changed files with 5070 additions and 374 deletions

View File

@@ -8,6 +8,7 @@ use App\Scolarite\Application\Port\FileStorage;
use function dirname;
use function file_put_contents;
use function fopen;
use function is_dir;
use function is_file;
use function is_string;
@@ -15,6 +16,12 @@ use function mkdir;
use Override;
use function realpath;
use RuntimeException;
use function sprintf;
use function str_starts_with;
use function unlink;
final readonly class LocalFileStorage implements FileStorage
@@ -50,4 +57,24 @@ final readonly class LocalFileStorage implements FileStorage
unlink($fullPath);
}
}
#[Override]
public function readStream(string $path): mixed
{
$fullPath = $this->storagePath . '/' . $path;
$realPath = realpath($fullPath);
$realStoragePath = realpath($this->storagePath);
if ($realPath === false || $realStoragePath === false || !str_starts_with($realPath, $realStoragePath)) {
throw new RuntimeException(sprintf('Impossible de lire le fichier : %s', $path));
}
$stream = fopen($realPath, 'r');
if ($stream === false) {
throw new RuntimeException(sprintf('Impossible de lire le fichier : %s', $path));
}
return $stream;
}
}