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
318 lines
12 KiB
PHP
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);
|
|
});
|
|
}
|
|
}
|