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:
@@ -6,6 +6,7 @@ namespace App\Scolarite\Infrastructure\Api\Controller;
|
||||
|
||||
use App\Administration\Infrastructure\Security\SecurityUser;
|
||||
use App\Scolarite\Application\Port\ClassStudentsReader;
|
||||
use App\Scolarite\Application\Port\FileStorage;
|
||||
use App\Scolarite\Domain\Model\Homework\HomeworkId;
|
||||
use App\Scolarite\Domain\Model\HomeworkSubmission\HomeworkSubmission;
|
||||
use App\Scolarite\Domain\Model\HomeworkSubmission\HomeworkSubmissionId;
|
||||
@@ -24,15 +25,15 @@ use function count;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
use function fclose;
|
||||
use function fpassthru;
|
||||
use function in_array;
|
||||
use function realpath;
|
||||
use function str_starts_with;
|
||||
|
||||
use RuntimeException;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\HeaderUtils;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
@@ -45,8 +46,7 @@ final readonly class TeacherSubmissionController
|
||||
private HomeworkSubmissionRepository $submissionRepository,
|
||||
private SubmissionAttachmentRepository $attachmentRepository,
|
||||
private ClassStudentsReader $classStudentsReader,
|
||||
#[Autowire('%kernel.project_dir%/var/storage')]
|
||||
private string $storageDir,
|
||||
private FileStorage $fileStorage,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ final readonly class TeacherSubmissionController
|
||||
}
|
||||
|
||||
#[Route('/api/homework/{homeworkId}/submissions/{submissionId}/attachments/{attachmentId}', name: 'api_teacher_submission_attachment_download', methods: ['GET'])]
|
||||
public function downloadAttachment(string $homeworkId, string $submissionId, string $attachmentId): BinaryFileResponse
|
||||
public function downloadAttachment(string $homeworkId, string $submissionId, string $attachmentId): StreamedResponse
|
||||
{
|
||||
$user = $this->getSecurityUser();
|
||||
$tenantId = TenantId::fromString($user->tenantId());
|
||||
@@ -268,20 +268,29 @@ final readonly class TeacherSubmissionController
|
||||
|
||||
foreach ($attachments as $attachment) {
|
||||
if ((string) $attachment->id === $attachmentId) {
|
||||
$fullPath = $this->storageDir . '/' . $attachment->filePath;
|
||||
$realPath = realpath($fullPath);
|
||||
$realStorageDir = realpath($this->storageDir);
|
||||
|
||||
if ($realPath === false || $realStorageDir === false || !str_starts_with($realPath, $realStorageDir)) {
|
||||
try {
|
||||
$stream = $this->fileStorage->readStream($attachment->filePath);
|
||||
} catch (RuntimeException) {
|
||||
throw new NotFoundHttpException('Pièce jointe non trouvée.');
|
||||
}
|
||||
|
||||
$response = new BinaryFileResponse($realPath);
|
||||
$response->setContentDisposition(
|
||||
ResponseHeaderBag::DISPOSITION_INLINE,
|
||||
$response = new StreamedResponse(static function () use ($stream): void {
|
||||
try {
|
||||
fpassthru($stream);
|
||||
} finally {
|
||||
fclose($stream);
|
||||
}
|
||||
});
|
||||
|
||||
$disposition = HeaderUtils::makeDisposition(
|
||||
HeaderUtils::DISPOSITION_INLINE,
|
||||
$attachment->filename,
|
||||
);
|
||||
|
||||
$response->headers->set('Content-Type', $attachment->mimeType);
|
||||
$response->headers->set('Content-Disposition', $disposition);
|
||||
$response->headers->set('Content-Length', (string) $attachment->fileSize);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user