ldc-dam/app/Http/Controllers/UploadController.php
Jérémy Munsch 9767e62c72
Update NPM deps and webpack.mix.js
composer require ldc/web-status-checker-laravel remove Old static status checker

Fix ImportMedia

WIP commands OK

many fixes

Fix and try to optimize folder component

Fix front icons + actions based on icons

Favico

front fix alert

Fix Media upload on depot

fix folder component buttons

Full front fix with perf due tu vuejs

Download medias

Navigate within medias superfix

Move media + loader

isLocked boolean and remove media fix

Folder scroll fix

arcadia link color red

Fix panier show external

Tons of fixes back as front

REwrited all
2022-07-22 17:00:48 +02:00

318 lines
12 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Enums\MediaExtension;
use App\Http\Requests\Bo\Ajax\UploadMediaFileRequest;
use App\Lib\ToolboxHelper;
use App\Models\Copyright;
use App\Models\Dossier;
use App\Models\Etiquette;
use App\Models\Langue;
use App\Models\Media;
use App\Models\Site;
use App\Models\Sujet;
use App\Models\TypeMedia;
use App\Models\User;
use App\Traits\Http\HandlesMedia;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException;
use Pion\Laravel\ChunkUpload\Receiver\FileReceiver;
class UploadController extends Controller
{
use HandlesMedia;
/**
* Show upload form
*
* @param Request $request
* @return \Illuminate\Contracts\Validation\Validator|\Illuminate\Contracts\Validation\Factory
*/
public function showUploadForm(Request $request)
{
// TODO: Quand le DAM sera ouvert au public, Enforce security with dynamic tokens.
// ---- Vérification du token de sécurité .
$token = $request->get('token');
if ($token != env('TOKEN_DEPOT', "c8c4613a-236c-4b06-95f6-a9c9c6c18861")) {
return abort(404);
}
$sites = Site::orderBy('libelle')->get();
return view('upload.show')->with([
'sites' => $sites,
]);
}
/**
* Asynchronous chunked upload file.
*
* @param \App\Http\Requests\Bo\Ajax\UploadMediaFileRequest $request
* @param \Pion\Laravel\ChunkUpload\Receiver\FileReceiver $receiver
* @return \Illuminate\Http\JsonResponse
* @throws \Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException If failed upload.
*/
public function uploadMediaFileIntoDepot(
UploadMediaFileRequest $request,
FileReceiver $receiver,
): JsonResponse {
/** @var \App\Models\Dossier */
$dossier = Dossier::where('id', intval($request->dossier_id))->firstOrFail();
// Check if the upload is success, throw exception or return response you need.
if ($receiver->isUploaded() === false) {
throw new UploadMissingFileException();
}
// Receive the file.
$save = $receiver->receive();
// Check if the upload has finished (in chunk mode it will send smaller files).
if ($save->isFinished()) {
/** @var \App\Models\User */
$user = auth()->user();
$uplodedFile = $save->getFile();
/** @throws \Illuminate\Validation\ValidationException */
$this->validateUploadedFile($uplodedFile);
/** @var \App\Models\Media */
$media = Media::whereId($request->media_id)
->whereHas('dossier', function ($q) use ($dossier) {
$q->whereId($dossier->id);
})->firstOrNew();
// Save the file and return any response you need.
return $this->createOrUpdateMedia($user, $uplodedFile, $media, $dossier);
}
// We are in chunk mode, lets send the current progress.
/** @var AbstractHandler $handler */
$handler = $save->handler();
return response()->json([
'done' => $handler->getPercentageDone()
]);
}
/**
* Asynchronous chunked upload file.
*
* @param \App\Http\Requests\Bo\Ajax\UploadMediaFileRequest $request
* @param \Pion\Laravel\ChunkUpload\Receiver\FileReceiver $receiver
* @param \App\Models\Sujet $sujet
* @param \App\Models\Dossier $dossier
* @return \Illuminate\Http\JsonResponse
* @throws \Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException If failed upload.
*/
public function uploadMediaFile(
UploadMediaFileRequest $request,
FileReceiver $receiver,
Sujet $sujet,
Dossier $dossier
): JsonResponse {
// Check if the upload is success, throw exception or return response you need.
if ($receiver->isUploaded() === false) {
throw new UploadMissingFileException();
}
// Receive the file.
$save = $receiver->receive();
// Check if the upload has finished (in chunk mode it will send smaller files).
if ($save->isFinished()) {
/** @var \App\Models\User */
$user = auth()->user();
$uplodedFile = $save->getFile();
/** @throws \Illuminate\Validation\ValidationException */
$this->validateUploadedFile($uplodedFile);
/** @var \App\Models\Media */
$media = Media::whereId($request->media_id)
->whereHas('sujet', function ($q) use ($sujet) {
$q->whereId($sujet->id);
})->whereHas('dossier', function ($q) use ($dossier) {
$q->whereId($dossier->id);
})->firstOrNew();
// Save the file and return any response you need.
return $this->createOrUpdateMedia($user, $uplodedFile, $media, $dossier, $sujet);
}
// We are in chunk mode, lets send the current progress.
/** @var AbstractHandler $handler */
$handler = $save->handler();
return response()->json([
'done' => $handler->getPercentageDone()
]);
}
/**
* Validate uploaded file
*
* @param \Illuminate\Http\UploadedFile $file
* @return void
* @throws \Illuminate\Validation\ValidationException If uploaded file is not valid.
*/
private function validateUploadedFile(UploadedFile $file)
{
Validator::make([
'file' => $file
], [
'file' => 'required|file|mimes:gif,jpeg,jpg,png,mp4,mp3,psd,ai,svg,pdf'
], [
'files.mimes' => trans('Ce type de fichier n\'est pas accepté.')
])->validate();
$this->validateExtension($file->getClientOriginalExtension());
}
/**
* Validate file extension matches allowed extensions enum
*
* @param string $extension
* @return void
*/
private function validateExtension(string $extension)
{
if (!\is_null(MediaExtension::tryFrom($extension))) {
ValidationException::withMessages([
'file' => trans('Ce type de fichier n\'est pas accepté.')
]);
}
}
/**
* Create or update media
*
* @param \App\Models\User $user
* @param \Illuminate\Http\UploadedFile $file
* @param \App\Models\Media $media
* @param \App\Models\Dossier $dossier
* @param \App\Models\Sujet|null $sujet
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Validation\ValidationException If $subject is missing and folder
* is not a system folder (Dossier dépot).
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
* (switch) .
*/
private function createOrUpdateMedia(
User $user,
UploadedFile $file,
Media $media,
Dossier $dossier,
Sujet|null $sujet = null
): JsonResponse {
// phpcs:enable
return DB::transaction(function () use ($user, $file, $media, $dossier, $sujet) {
if (!$dossier->system and !$sujet) {
throw ValidationException::withMessages([
'file' => 'Cannot put media inside a non system folder (depot) without a subject'
]);
}
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$storage = Storage::disk('media');
$isNewMedia = !$media->exists;
$mediaFolderName = $this->getCurentMediaFolderName();
// * File size
$fileSize = $file->getSize();
$sanitizedFileName = ToolboxHelper::sanitizeFileName($file->getClientOriginalName());
/** @var string */
$sanitizedFileBasename = \pathinfo($sanitizedFileName, \PATHINFO_BASENAME);
/** @var string */
$sanitizedFileExtension = \pathinfo($sanitizedFileName, \PATHINFO_EXTENSION);
// * Validate Extension
/** @throws \ValueError If value is not defined in enum */
$mediaExtension = MediaExtension::from($sanitizedFileExtension);
if (!$isNewMedia) {
// Supprimer les vielles images.
$media->deleteFilesOnAllPath();
}
// * New folder attribution
$media->folder = $mediaFolderName;
// * New Image, New uuid.
$media->uid = Str::uuid();
// * New Image extension
$media->extension = $mediaExtension;
// * New Image size
$media->taille = $fileSize ? $fileSize : 0;
// * Le media n'est pas une image par défaut.
$media->isDefault = false;
// TODO: Supprimer old fichier dans le cas d'un update.
// * On déplace le fichier dans le répertoire des médias.
/** @throws \FileException */
$file->move($storage->path($media->folder), "{$media->uid}.{$media->extension->value}");
// * Si on upload un média pour remplacer un fichier par un autre
if ($isNewMedia) {
$media->libelle = Str::limit($sanitizedFileBasename, 50, '');
$media->owner()->associate($user);
$media->dossier()->associate($dossier);
$media->sujet()->associate($sujet);
// * Par défaut FR
$media->langue()->associate(Langue::getDefaultLang());
// * Par défaut propriété de la marque
$media->copyright()->associate(Copyright::getBrandCopyright());
$media->etiquette()->associate(Etiquette::getDefaultEtiquette());
}
switch ($media->extension) {
case MediaExtension::gif:
case MediaExtension::jpeg:
case MediaExtension::jpg:
case MediaExtension::png:
case MediaExtension::ai:
case MediaExtension::pdf:
case MediaExtension::psd:
$dimensions = ToolboxHelper::getImageDimensions($media->full_path);
if ($dimensions) {
$media->resolution = $dimensions['resolutionX'];
$media->largeur = $dimensions['width'];
$media->hauteur = $dimensions['height'];
$media->largeur_mm = !empty($media->resolution) ? ceil($media->largeur * 10) : 0;
$media->hauteur_mm = !empty($media->resolution) ? ceil($media->hauteur * 10) : 0;
}
// ---- Creation des vignettes de base
$media->createThumbnail();
// ---- Creation des vignettes en lien avec le sujet du média
$media->createSubjectThumbnails();
break;
case MediaExtension::mp4:
if ($dimensions = ToolboxHelper::getId3VideoDimensions($media->full_path)) {
$media->largeur = $dimensions['width'];
$media->hauteur = $dimensions['height'];
}
// Fall-through .
case MediaExtension::mp3:
$media->duree = ToolboxHelper::getId3Playtime($media->full_path);
break;
} //end switch
$media->typeMedia()->associate(TypeMedia::getMediaType($media->extension));
$media->saveOrFail();
// * Get props inserted by DB.
$media->refresh();
return response()->json($media);
});
}
}