'bucket-de-test']); Storage::fake('s3'); } test('tant que le bucket s3 n’est pas configuré, le dépôt de fichier est masqué et refusé', function () { $classe = Classe::factory()->create(); $eleve = Eleve::factory()->create(['classe_id' => $classe->id]); $devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]); eleve($this, $eleve)->get(route('devoirs.eleve.show', $devoir))->assertOk()->assertDontSee('Joindre un fichier'); eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [ 'fichier' => UploadedFile::fake()->create('devoir.pdf', 100, 'application/pdf'), ])->assertStatus(503); }); test('un élève peut rendre un devoir avec un fichier seul, sans texte', function () { avecDisqueS3Factice(); $classe = Classe::factory()->create(); $eleve = Eleve::factory()->create(['classe_id' => $classe->id]); $devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]); eleve($this, $eleve)->get(route('devoirs.eleve.show', $devoir))->assertOk()->assertSee('Joindre un fichier'); eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [ 'fichier' => UploadedFile::fake()->create('devoir.pdf', 100, 'application/pdf'), ])->assertRedirect(); $rendu = RenduDevoir::where('devoir_id', $devoir->id)->where('eleve_id', $eleve->id)->first(); expect($rendu)->not->toBeNull(); expect($rendu->reponse)->toBeNull(); expect($rendu->aUnFichier())->toBeTrue(); expect($rendu->fichier_nom_original)->toBe('devoir.pdf'); Storage::disk('s3')->assertExists($rendu->fichier_chemin); }); test('un rendu sans réponse ni fichier est refusé', function () { avecDisqueS3Factice(); $classe = Classe::factory()->create(); $eleve = Eleve::factory()->create(['classe_id' => $classe->id]); $devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]); eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [])->assertSessionHasErrors(['reponse', 'fichier']); expect(RenduDevoir::count())->toBe(0); }); test('un fichier trop lourd ou d’une extension refusée est rejeté', function () { avecDisqueS3Factice(); $classe = Classe::factory()->create(); $eleve = Eleve::factory()->create(['classe_id' => $classe->id]); $devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]); eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [ 'fichier' => UploadedFile::fake()->create('trop-gros.pdf', 11 * 1024, 'application/pdf'), ])->assertSessionHasErrors('fichier'); eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [ 'fichier' => UploadedFile::fake()->create('script.exe', 10, 'application/x-msdownload'), ])->assertSessionHasErrors('fichier'); expect(RenduDevoir::count())->toBe(0); }); test('remplacer son fichier supprime l’ancien de l’object storage, un nouvel envoi en texte seul le conserve', function () { avecDisqueS3Factice(); $classe = Classe::factory()->create(); $eleve = Eleve::factory()->create(['classe_id' => $classe->id]); $devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]); eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [ 'fichier' => UploadedFile::fake()->create('premier.pdf', 100, 'application/pdf'), ])->assertRedirect(); $cheminPremier = RenduDevoir::first()->fichier_chemin; Storage::disk('s3')->assertExists($cheminPremier); // Un nouvel envoi en texte seul (pas de nouveau fichier) garde l'ancien fichier. eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), ['reponse' => 'Je précise ma réponse'])->assertRedirect(); $rendu = RenduDevoir::first(); expect($rendu->fichier_chemin)->toBe($cheminPremier)->and($rendu->reponse)->toBe('Je précise ma réponse'); Storage::disk('s3')->assertExists($cheminPremier); // Un nouveau fichier remplace l'ancien, qui est supprimé de l'object storage. eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [ 'fichier' => UploadedFile::fake()->create('second.pdf', 100, 'application/pdf'), ])->assertRedirect(); Storage::disk('s3')->assertMissing($cheminPremier); expect(RenduDevoir::count())->toBe(1); }); test('seul le prof propriétaire peut télécharger le fichier rendu par un élève', function () { avecDisqueS3Factice(); $classe = Classe::factory()->create(); $eleve = Eleve::factory()->create(['classe_id' => $classe->id]); $devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]); eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [ 'fichier' => UploadedFile::fake()->create('devoir.pdf', 100, 'application/pdf'), ])->assertRedirect(); $rendu = RenduDevoir::first(); commeProf($this, $classe->prof)->get(route('mes-classes.devoirs.telecharger', [$classe, $devoir, $rendu]))->assertRedirect(); $autreClasse = Classe::factory()->create(); commeProf($this, $autreClasse->prof)->get(route('mes-classes.devoirs.telecharger', [$classe, $devoir, $rendu]))->assertForbidden(); }); test('le prof voit le fichier déposé par un élève dans la page du devoir', function () { avecDisqueS3Factice(); $classe = Classe::factory()->create(); $eleve = Eleve::factory()->create(['classe_id' => $classe->id]); $devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]); eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [ 'fichier' => UploadedFile::fake()->create('rapport-reseau.pdf', 100, 'application/pdf'), ])->assertRedirect(); commeProf($this, $classe->prof)->get(route('mes-classes.devoirs.show', [$classe, $devoir])) ->assertSee('rapport-reseau.pdf'); }); test('purger une classe archivée supprime aussi les fichiers de ses rendus sur l’object storage', function () { avecDisqueS3Factice(); $classe = Classe::factory()->create(); $eleve = Eleve::factory()->create(['classe_id' => $classe->id]); $devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]); eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), [ 'fichier' => UploadedFile::fake()->create('devoir.pdf', 100, 'application/pdf'), ])->assertRedirect(); $chemin = RenduDevoir::first()->fichier_chemin; Storage::disk('s3')->assertExists($chemin); $classe->forceFill(['archivee_a' => now()->subDays(91)])->save(); $this->artisan('classes:purger-archivees'); Storage::disk('s3')->assertMissing($chemin); expect(RenduDevoir::count())->toBe(0); });