diff --git a/app/Enums/Documents/TypeEnum.php b/app/Enums/Documents/TypeEnum.php index bd3006b..60935d1 100644 --- a/app/Enums/Documents/TypeEnum.php +++ b/app/Enums/Documents/TypeEnum.php @@ -19,8 +19,8 @@ final class TypeEnum extends BaseEnumRoutable protected static function values(): array { return [ - 'pdf' => 1, - 'mp4' => 2, + 'pdf' => 'pdf', + 'mp4' => 'mp4', ]; } diff --git a/app/Http/Controllers/Bo/DocumentController.php b/app/Http/Controllers/Bo/DocumentController.php index b0c8001..db176fa 100644 --- a/app/Http/Controllers/Bo/DocumentController.php +++ b/app/Http/Controllers/Bo/DocumentController.php @@ -5,11 +5,13 @@ namespace App\Http\Controllers\Bo; use App\Http\Controllers\Controller; use App\Http\Requests\Bo\Documents\StoreDocumentRequest; use App\Http\Requests\Bo\Documents\UpdateDocumentRequest; +use App\Http\Requests\Bo\UploadRequest; use App\Models\Directory; use App\Models\Document; use App\Models\Tag; use App\Traits\Controllers\ChangesModelOrder; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\DB; @@ -190,10 +192,10 @@ class DocumentController extends Controller /** * Download the document * - * @param mixed $uuid + * @param string $uuid * @return \Symfony\Component\HttpFoundation\BinaryFileResponse */ - public function download($uuid) + public function download(string $uuid) { $doc = Document::where('uuid', $uuid)->firstOrFail(); $pathToFile = public_path() . Storage::url('docs/' . $doc->uuid . '.' . $doc->type); @@ -201,17 +203,12 @@ class DocumentController extends Controller } /** - * @param \Illuminate\Http\Request $request + * @param \App\Http\Requests\Bo\UploadRequest $request * @return \Illuminate\Http\JsonResponse * @throws \Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException Bla. */ - public function upload(Request $request) + public function upload(UploadRequest $request) { - if (isset($request->uuid)) { - $uuid = $request->uuid; - } else { - $uuid = false; - } // Create the file receiver. $receiver = new FileReceiver("file", $request, HandlerFactory::classFromRequest($request)); // Check if the upload is success, throw exception or return response you need. @@ -224,7 +221,7 @@ class DocumentController extends Controller if ($save->isFinished()) { // Save the file and return any response you need, current example uses `move` function. // If you are not using move, you need to manually delete the file: unlink($save->getFile()->getPathname()). - return $this->saveFile($save->getFile(), $uuid); + return $this->saveFile($save->getFile(), $request->uuid); } // We are in chunk mode, lets send the current progress. /** @var AbstractHandler $handler */ @@ -237,28 +234,19 @@ class DocumentController extends Controller /** * @param \Illuminate\Http\UploadedFile $file - * @param mixed $uuid + * @param string|null $uuid * @return \Illuminate\Http\JsonResponse - * @throws \Illuminate\Contracts\Container\BindingResolutionException Bla. */ - protected function saveFile(UploadedFile $file, $uuid) + protected function saveFile(UploadedFile $file, ?string $uuid): JsonResponse { - if ($uuid === false) { - $uuid = sprintf( - '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', - mt_rand(0, 0xffff), - mt_rand(0, 0xffff), - mt_rand(0, 0xffff), - mt_rand(0, 0x0fff) | 0x4000, - mt_rand(0, 0x3fff) | 0x8000, - mt_rand(0, 0xffff), - mt_rand(0, 0xffff), - mt_rand(0, 0xffff) - ); - } - $finalPath = storage_path('app/public/docs/'); - // Move the file name. - $file->move($finalPath, $uuid . '.' . $file->getClientOriginalExtension()); + /** @var \Illuminate\Filesystem\FilesystemAdapter */ + $disk = Storage::disk('docs'); + $uuid = $uuid ?: Str::uuid(); + + /** @var \Illuminate\Http\UploadedFile $file */ + $filename = $uuid . '.' . $file->guessExtension(); + $disk->putFileAs('', $file, $filename); + return response()->json([ 'uid' => $uuid, ]); diff --git a/app/Http/Requests/Bo/Documents/StoreDocumentRequest.php b/app/Http/Requests/Bo/Documents/StoreDocumentRequest.php index 63568e2..070d9ae 100644 --- a/app/Http/Requests/Bo/Documents/StoreDocumentRequest.php +++ b/app/Http/Requests/Bo/Documents/StoreDocumentRequest.php @@ -3,8 +3,11 @@ namespace App\Http\Requests\Bo\Documents; use App\Enums\Documents\LangEnum; +use App\Enums\Documents\TypeEnum; +use App\Lib\Helpers\FileStorageHelper; use App\Models\Document; use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Support\Facades\Storage; use Kwaadpepper\Enum\Rules\EnumIsValidRule; class StoreDocumentRequest extends FormRequest @@ -35,6 +38,19 @@ class StoreDocumentRequest extends FormRequest ->value('directory_id') ]); } + // * Sanitize Path + if (!empty($this->path)) { + $filename = $this->path; + $refMethod = new \ReflectionMethod(FileStorageHelper::class, 'sanitizeFileName'); + $refMethod->setAccessible(true); + $filename = \pathinfo( + $refMethod->invoke(null, htmlspecialchars($filename), false), + \PATHINFO_BASENAME + ); + $this->merge([ + 'path' => $filename + ]); + } } /** @@ -44,11 +60,30 @@ class StoreDocumentRequest extends FormRequest */ public function rules() { + /** @var \Illuminate\Filesystem\FilesystemAdapter */ + $disk = Storage::disk('docs'); return [ 'directory_id' => 'required|integer', 'document_id' => 'sometimes:directory_id|nullable|integer', + 'uuid' => [ + // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed + 'required', 'uuid', function ($attribute, $value, $fail) use ($disk) { + if ($this->type and \in_array($this->type, TypeEnum::toValues())) { + $value = "{$value}.{$this->type}"; + } + if (!$disk->has($value)) { + $path = $this->path ?? $this->value ?? 'not found'; + $fail(\trans('Le fichier :filename n\'est pas présent dans le système de fichier', [ + 'filename' => $path + ])); + } + } + ], 'title' => 'required|min:3|max:255', - 'type' => 'required|min:3|max:255', + 'type' => [ + 'required', + new EnumIsValidRule(TypeEnum::class) + ], 'path' => 'required|min:3|max:255', 'lang' => [ 'required', diff --git a/app/Http/Requests/Bo/UploadRequest.php b/app/Http/Requests/Bo/UploadRequest.php new file mode 100644 index 0000000..a2e6965 --- /dev/null +++ b/app/Http/Requests/Bo/UploadRequest.php @@ -0,0 +1,30 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'uuid' => 'nullable|uuid' + ]; + } +} diff --git a/app/Models/Document.php b/app/Models/Document.php index d3a38ac..85f10da 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -2,27 +2,29 @@ namespace App\Models; -use App\Enums\TypeEnum; +use App\Enums\Documents\LangEnum; +use App\Enums\Documents\TypeEnum; use App\Lib\Helpers\ToolboxHelper; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Storage; -use Illuminate\Support\Str; +use Kwaadpepper\Enum\Traits\CastsEnums; /** * @property integer $id * @property integer $uuid * @property string $title - * @property TypeEnum $type + * @property \App\Enums\Documents\TypeEnum $type * @property integer $directory_id * @property integer $document_id * @property string $path - * @property LangEnum $lang + * @property \App\Enums\Documents\LangEnum $lang * @property boolean $status * @property integer $order */ class Document extends Model { + use CastsEnums; use HasFactory; /** @@ -69,7 +71,6 @@ class Document extends Model protected static function booted() { static::creating(function (self $model) { - $model->uuid = Str::uuid(); self::assertFieldIsUnique('title', $model->title); self::setOrder($model); }); diff --git a/config/filesystems.php b/config/filesystems.php index 0dece94..cca7538 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -42,6 +42,13 @@ return [ 'visibility' => 'public', ], + 'docs' => [ + 'driver' => 'local', + 'root' => storage_path('app/public/docs'), + 'url' => env('APP_URL') . '/storage/docs', + 'visibility' => 'public', + ], + 's3' => [ 'driver' => 's3', 'key' => env('AWS_ACCESS_KEY_ID'),