L'élève peut désormais répondre à un devoir via un éditeur WYSIWYG, joindre des fichiers (PDF, JPEG, PNG, DOCX), sauvegarder un brouillon et soumettre définitivement son rendu. Le système détecte automatiquement les soumissions en retard par rapport à la date d'échéance. Côté enseignant, une page dédiée affiche la liste complète des élèves avec leur statut (soumis, en retard, brouillon, non rendu), le détail de chaque rendu avec ses pièces jointes téléchargeables, et les statistiques de rendus par classe.
131 lines
4.4 KiB
PHP
131 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Unit\Scolarite\Application\Command\UploadSubmissionAttachment;
|
|
|
|
use App\Administration\Domain\Model\User\UserId;
|
|
use App\Scolarite\Application\Command\UploadSubmissionAttachment\UploadSubmissionAttachmentCommand;
|
|
use App\Scolarite\Application\Command\UploadSubmissionAttachment\UploadSubmissionAttachmentHandler;
|
|
use App\Scolarite\Application\Port\FileStorage;
|
|
use App\Scolarite\Domain\Exception\RenduDejaSoumisException;
|
|
use App\Scolarite\Domain\Model\Homework\HomeworkId;
|
|
use App\Scolarite\Domain\Model\HomeworkSubmission\HomeworkSubmission;
|
|
use App\Scolarite\Infrastructure\Persistence\InMemory\InMemoryHomeworkSubmissionRepository;
|
|
use App\Shared\Domain\Clock;
|
|
use App\Shared\Domain\Tenant\TenantId;
|
|
use DateTimeImmutable;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class UploadSubmissionAttachmentHandlerTest extends TestCase
|
|
{
|
|
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
|
|
private const string HOMEWORK_ID = '550e8400-e29b-41d4-a716-446655440050';
|
|
private const string STUDENT_ID = '550e8400-e29b-41d4-a716-446655440060';
|
|
|
|
private InMemoryHomeworkSubmissionRepository $submissionRepository;
|
|
private string $tempFile;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->submissionRepository = new InMemoryHomeworkSubmissionRepository();
|
|
$this->tempFile = tempnam(sys_get_temp_dir(), 'e2e_upload_');
|
|
file_put_contents($this->tempFile, 'fake PDF content');
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
if (file_exists($this->tempFile)) {
|
|
unlink($this->tempFile);
|
|
}
|
|
}
|
|
|
|
#[Test]
|
|
public function itUploadsAttachmentForDraftSubmission(): void
|
|
{
|
|
$submission = $this->createDraftSubmission();
|
|
$this->submissionRepository->save($submission);
|
|
|
|
$handler = $this->createHandler();
|
|
$command = new UploadSubmissionAttachmentCommand(
|
|
tenantId: self::TENANT_ID,
|
|
submissionId: (string) $submission->id,
|
|
filename: 'devoir.pdf',
|
|
mimeType: 'application/pdf',
|
|
fileSize: 1024,
|
|
tempFilePath: $this->tempFile,
|
|
);
|
|
|
|
$attachment = $handler($command);
|
|
|
|
self::assertSame('devoir.pdf', $attachment->filename);
|
|
self::assertSame('application/pdf', $attachment->mimeType);
|
|
self::assertSame(1024, $attachment->fileSize);
|
|
self::assertStringContainsString('submissions/', $attachment->filePath);
|
|
}
|
|
|
|
#[Test]
|
|
public function itRejectsUploadOnSubmittedSubmission(): void
|
|
{
|
|
$submission = $this->createDraftSubmission();
|
|
$submission->soumettre(
|
|
dueDate: new DateTimeImmutable('2026-04-15'),
|
|
now: new DateTimeImmutable('2026-03-24 11:00:00'),
|
|
);
|
|
$this->submissionRepository->save($submission);
|
|
|
|
$handler = $this->createHandler();
|
|
$command = new UploadSubmissionAttachmentCommand(
|
|
tenantId: self::TENANT_ID,
|
|
submissionId: (string) $submission->id,
|
|
filename: 'devoir.pdf',
|
|
mimeType: 'application/pdf',
|
|
fileSize: 1024,
|
|
tempFilePath: $this->tempFile,
|
|
);
|
|
|
|
$this->expectException(RenduDejaSoumisException::class);
|
|
|
|
$handler($command);
|
|
}
|
|
|
|
private function createDraftSubmission(): HomeworkSubmission
|
|
{
|
|
return HomeworkSubmission::creerBrouillon(
|
|
tenantId: TenantId::fromString(self::TENANT_ID),
|
|
homeworkId: HomeworkId::fromString(self::HOMEWORK_ID),
|
|
studentId: UserId::fromString(self::STUDENT_ID),
|
|
responseHtml: '<p>Ma réponse</p>',
|
|
now: new DateTimeImmutable('2026-03-24 10:00:00'),
|
|
);
|
|
}
|
|
|
|
private function createHandler(): UploadSubmissionAttachmentHandler
|
|
{
|
|
$fileStorage = new class implements FileStorage {
|
|
public function upload(string $path, mixed $content, string $mimeType): string
|
|
{
|
|
return $path;
|
|
}
|
|
|
|
public function delete(string $path): void
|
|
{
|
|
}
|
|
};
|
|
|
|
$clock = new class implements Clock {
|
|
public function now(): DateTimeImmutable
|
|
{
|
|
return new DateTimeImmutable('2026-03-24 10:00:00');
|
|
}
|
|
};
|
|
|
|
return new UploadSubmissionAttachmentHandler(
|
|
$this->submissionRepository,
|
|
$fileStorage,
|
|
$clock,
|
|
);
|
|
}
|
|
}
|