validate([ 'type' => 'required|in:devis,bon_commande,bon_livraison,facture,autre', 'fichier' => [ 'required', 'file', 'max:20480', // 20 Mo max 'mimes:pdf,jpg,jpeg,png,gif,webp,doc,docx,xls,xlsx,odt,ods,csv,zip', ], 'description' => 'nullable|string|max:500', ], [ 'fichier.mimes' => 'Types autorisés : PDF, images, Word, Excel, OpenDocument, CSV, ZIP.', 'fichier.max' => 'La pièce jointe ne peut pas dépasser 20 Mo.', ]); $fichier = $request->file('fichier'); $chemin = $fichier->store( 'commandes/' . $commande->id, 'private' ); $commande->piecesJointes()->create([ 'user_id' => $request->user()->id, 'type' => $request->type, 'nom_original' => $fichier->getClientOriginalName(), 'chemin' => $chemin, 'mime_type' => $fichier->getMimeType(), 'taille' => $fichier->getSize(), 'description' => $request->description, ]); return back()->with('success', 'Pièce jointe ajoutée avec succès.'); } /** * Upload une pièce jointe sur un contrat. */ public function storeContrat(Request $request, \App\Models\Contrat $contrat): RedirectResponse { $request->validate([ 'type' => 'required|in:contrat,avenant,facture,autre', 'fichier' => [ 'required', 'file', 'max:20480', // 20 Mo max 'mimes:pdf,jpg,jpeg,png,gif,webp,doc,docx,xls,xlsx,odt,ods,csv,zip', ], 'description' => 'nullable|string|max:500', ], [ 'fichier.mimes' => 'Types autorisés : PDF, images, Word, Excel, OpenDocument, CSV, ZIP.', 'fichier.max' => 'La pièce jointe ne peut pas dépasser 20 Mo.', ]); $fichier = $request->file('fichier'); $chemin = $fichier->store( 'contrats/' . $contrat->id, 'private' ); $contrat->piecesJointes()->create([ 'user_id' => $request->user()->id, 'type' => $request->type, 'nom_original' => $fichier->getClientOriginalName(), 'chemin' => $chemin, 'mime_type' => $fichier->getMimeType(), 'taille' => $fichier->getSize(), 'description' => $request->description, ]); return back()->with('success', 'Pièce jointe ajoutée avec succès au contrat.'); } /** * Télécharger une pièce jointe (accès sécurisé, sans URL publique). */ public function download(PieceJointe $pieceJointe): StreamedResponse { // Vérifier que l'utilisateur est authentifié (middleware auth déjà sur le groupe) abort_unless(Storage::disk('private')->exists($pieceJointe->chemin), 404); return Storage::disk('private')->download( $pieceJointe->chemin, $pieceJointe->nom_original ); } /** * Supprimer une pièce jointe. */ public function destroy(PieceJointe $pieceJointe): RedirectResponse { $this->authorize('delete', $pieceJointe); $pieceJointe->supprimer(); return back()->with('success', 'Pièce jointe supprimée.'); } }