feat: Provisionner automatiquement un nouvel établissement
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:
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Scolarite\Infrastructure\Api\Provider;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Administration\Domain\Model\User\Role;
|
||||
use App\Administration\Infrastructure\Security\SecurityUser;
|
||||
use App\Scolarite\Application\Query\GetClassStatisticsDetail\ClassStatisticsDetailDto;
|
||||
use App\Scolarite\Application\Query\GetClassStatisticsDetail\GetClassStatisticsDetailQuery;
|
||||
use App\Scolarite\Application\Service\StatisticsExporter;
|
||||
use App\Shared\Infrastructure\Tenant\TenantContext;
|
||||
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
|
||||
use Override;
|
||||
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
use Symfony\Component\Messenger\HandleTrait;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
|
||||
/**
|
||||
* @implements ProviderInterface<Response>
|
||||
*/
|
||||
final class TeacherStatisticsExportProvider implements ProviderInterface
|
||||
{
|
||||
use HandleTrait;
|
||||
|
||||
public function __construct(
|
||||
MessageBusInterface $queryBus,
|
||||
private readonly TenantContext $tenantContext,
|
||||
private readonly Security $security,
|
||||
private readonly StatisticsExporter $exporter,
|
||||
) {
|
||||
$this->messageBus = $queryBus;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): Response
|
||||
{
|
||||
if (!$this->tenantContext->hasTenant()) {
|
||||
throw new UnauthorizedHttpException('Bearer', 'Tenant non défini.');
|
||||
}
|
||||
|
||||
$user = $this->security->getUser();
|
||||
|
||||
if (!$user instanceof SecurityUser) {
|
||||
throw new UnauthorizedHttpException('Bearer', 'Authentification requise.');
|
||||
}
|
||||
|
||||
if (!in_array(Role::PROF->value, $user->getRoles(), true)) {
|
||||
throw new AccessDeniedHttpException('Accès réservé aux enseignants.');
|
||||
}
|
||||
|
||||
/** @var array<string, mixed> $filters */
|
||||
$filters = $context['filters'] ?? [];
|
||||
/** @var string|null $classId */
|
||||
$classId = $filters['classId'] ?? null;
|
||||
/** @var string|null $subjectId */
|
||||
$subjectId = $filters['subjectId'] ?? null;
|
||||
/** @var string|null $className */
|
||||
$className = $filters['className'] ?? 'Classe';
|
||||
/** @var string|null $subjectName */
|
||||
$subjectName = $filters['subjectName'] ?? 'Matière';
|
||||
|
||||
if (!is_string($classId) || $classId === '') {
|
||||
throw new BadRequestHttpException('Le paramètre classId est requis.');
|
||||
}
|
||||
|
||||
if (!is_string($subjectId) || $subjectId === '') {
|
||||
throw new BadRequestHttpException('Le paramètre subjectId est requis.');
|
||||
}
|
||||
|
||||
/** @var ClassStatisticsDetailDto $dto */
|
||||
$dto = $this->handle(new GetClassStatisticsDetailQuery(
|
||||
teacherId: $user->userId(),
|
||||
classId: $classId,
|
||||
subjectId: $subjectId,
|
||||
tenantId: (string) $this->tenantContext->getCurrentTenantId(),
|
||||
));
|
||||
|
||||
$csv = $this->exporter->exportClassToCsv($dto, (string) $className, (string) $subjectName);
|
||||
|
||||
// Sanitize filename: remove characters dangerous in Content-Disposition
|
||||
$safeFilename = str_replace(['"', "\r", "\n", '/', '\\'], '', sprintf('statistiques-%s-%s.csv', $className, $subjectName));
|
||||
|
||||
return new Response(
|
||||
content: $csv,
|
||||
headers: [
|
||||
'Content-Type' => 'text/csv; charset=UTF-8',
|
||||
'Content-Disposition' => sprintf('attachment; filename="%s"', $safeFilename),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user