feat: Provisionner automatiquement un nouvel établissement
Some checks failed
CI / Backend Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Naming Conventions (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 3575d095a1
106 changed files with 9586 additions and 380 deletions

View File

@@ -0,0 +1,84 @@
<?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\GetEvaluationDifficulty\EvaluationDifficultyDto;
use App\Scolarite\Application\Query\GetEvaluationDifficulty\GetEvaluationDifficultyQuery;
use App\Scolarite\Infrastructure\Api\Resource\EvaluationDifficultyResource;
use App\Shared\Infrastructure\Tenant\TenantContext;
use function in_array;
use Override;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\Messenger\HandleTrait;
use Symfony\Component\Messenger\MessageBusInterface;
/**
* @implements ProviderInterface<EvaluationDifficultyResource>
*/
final class EvaluationDifficultyProvider implements ProviderInterface
{
use HandleTrait;
public function __construct(
MessageBusInterface $queryBus,
private readonly TenantContext $tenantContext,
private readonly Security $security,
) {
$this->messageBus = $queryBus;
}
#[Override]
public function provide(Operation $operation, array $uriVariables = [], array $context = []): EvaluationDifficultyResource
{
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 list<EvaluationDifficultyDto> $results */
$results = $this->handle(new GetEvaluationDifficultyQuery(
teacherId: $user->userId(),
tenantId: (string) $this->tenantContext->getCurrentTenantId(),
));
$resource = new EvaluationDifficultyResource();
$resource->teacherId = $user->userId();
foreach ($results as $dto) {
$resource->evaluations[] = [
'evaluationId' => $dto->evaluationId,
'title' => $dto->title,
'classId' => $dto->classId,
'className' => $dto->className,
'subjectId' => $dto->subjectId,
'subjectName' => $dto->subjectName,
'date' => $dto->date,
'average' => $dto->average,
'gradedCount' => $dto->gradedCount,
'subjectAverage' => $dto->subjectAverage,
'percentile' => $dto->percentile,
];
}
return $resource;
}
}