Paillasse/portail/app/Services/Stockage/StockageTravauxEleves.php
Adam Belkacemi 6ea7a1cc16 ajoute le stockage S3 des devoirs maison (bloc B, dernier chantier)
Dépôt de fichier en plus du texte libre pour les devoirs maison, stocké
sur Hetzner Object Storage (jamais sur le disque du serveur), masqué
côté élève tant que le bucket n'est pas configuré. Purge RGPD étendue
pour supprimer aussi les fichiers d'Object Storage. Ansible lit les
identifiants depuis un fichier que seul Adam peut créer sur le serveur
(runbook docs/runbooks/stockage-s3.md) ; le bloc B du CLAUDE.md est
maintenant complet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-14 09:52:15 +02:00

58 lines
1.8 KiB
PHP

<?php
namespace App\Services\Stockage;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
/**
* Stockage des rendus de devoirs maison sur Object Storage (bloc B,
* Hetzner, 2026-10-14) : jamais sur le disque du serveur. Le bouton de
* dépôt de fichier n'apparaît que si le disque est vraiment configuré
* (CLAUDE.md : pas de fonction qui a l'air de marcher sans vraiment
* marcher) — tant qu'Adam n'a pas créé le bucket, seul le texte libre
* reste proposé.
*/
class StockageTravauxEleves
{
public const TAILLE_MAX_OCTETS = 10 * 1024 * 1024; // 10 Mo
public const EXTENSIONS_ACCEPTEES = ['pdf', 'doc', 'docx', 'odt', 'txt', 'png', 'jpg', 'jpeg', 'zip'];
public static function disponible(): bool
{
return filled(config('filesystems.disks.s3.bucket'));
}
/**
* @return array{chemin: string, nom_original: string, taille_octets: int}
*/
public static function stocker(UploadedFile $fichier, string $devoirId, string $eleveId): array
{
$chemin = $fichier->storeAs(
"devoirs/{$devoirId}/{$eleveId}",
now()->format('Ymd-His').'-'.Str::random(8).'.'.$fichier->getClientOriginalExtension(),
's3'
);
return [
'chemin' => $chemin,
'nom_original' => $fichier->getClientOriginalName(),
'taille_octets' => $fichier->getSize(),
];
}
public static function supprimer(?string $chemin): void
{
if ($chemin !== null) {
Storage::disk('s3')->delete($chemin);
}
}
/** Lien valable 5 minutes, jamais le fichier servi en clair par le portail. */
public static function urlTemporaire(string $chemin): string
{
return Storage::disk('s3')->temporaryUrl($chemin, now()->addMinutes(5));
}
}