diff --git a/src/MediaController.php b/src/MediaController.php index 6ee29d3..c18a5e5 100644 --- a/src/MediaController.php +++ b/src/MediaController.php @@ -5,8 +5,6 @@ namespace Zoomyboy\MedialibraryHelper; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Validation\Rule; -use Illuminate\Validation\ValidationException; use Spatie\Image\Image; use Spatie\LaravelData\DataCollection; use Spatie\MediaLibrary\HasMedia; @@ -14,7 +12,7 @@ use Spatie\MediaLibrary\MediaCollections\Exceptions\InvalidBase64Data; use Spatie\MediaLibrary\MediaCollections\FileAdder; use Spatie\MediaLibrary\MediaCollections\MediaCollection; use Spatie\MediaLibrary\MediaCollections\Models\Media; -use Symfony\Component\HttpFoundation\File\File; +use Zoomyboy\MedialibraryHelper\Rules\ModelRule; class MediaController { @@ -23,12 +21,11 @@ class MediaController public function store(Request $request) { $request->validate([ - 'model' => ['required', 'string', Rule::in(app('media-library-helpers')->keys())], - 'id' => 'required', + 'parent' => ['required', new ModelRule()], ]); - $model = $this->validateModel($request); - $collection = $model->getMediaCollection($request->input('collection')); + $model = ModelRule::getModel($request->input('parent')); + $collection = ModelRule::getCollection($request->input('parent')); $isSingle = 1 === $collection->collectionSizeLimit; $this->authorize('storeMedia', [$model, $collection->name]); @@ -116,26 +113,6 @@ class MediaController return property_exists($collection, $callback); } - protected function validateModel(Request $request): HasMedia - { - $model = app('media-library-helpers')->get($request->input('model')); - - $request->validate([ - 'collection' => [ - 'required', - 'string', - Rule::in((new $model())->getRegisteredMediaCollections()->pluck('name')), - ], - ]); - - $model = $model::find($request->input('id')); - if (!$model) { - throw ValidationException::withMessages(['model' => 'nicht gefunden']); - } - - return $model; - } - protected function fileAdderFromData($model, $data, $collection): FileAdder { $maxWidth = $collection->runCallback('maxWidth', 9); diff --git a/src/Rules/ModelRule.php b/src/Rules/ModelRule.php new file mode 100644 index 0000000..9e3ca2f --- /dev/null +++ b/src/Rules/ModelRule.php @@ -0,0 +1,59 @@ +make([$attribute => $value], [ + "{$attribute}.id" => 'required|integer|gt:0', + "{$attribute}.model" => ['required', 'string', Rule::in(app('media-library-helpers')->keys())], + "{$attribute}.collection" => 'required|string', + ])->validate(); + + $this->model = data_get($value, 'model'); + $this->id = data_get($value, 'id'); + $this->collection = data_get($value, 'collection'); + + + $model = app('media-library-helpers')->get($this->model); + app(Factory::class)->make([$attribute => $value], [ + "{$attribute}.collection" => ['required', Rule::in((new $model())->getRegisteredMediaCollections()->pluck('name'))], + "{$attribute}.id" => ['required', 'exists:' . (new $model)->getTable() . ',id'], + ])->validate(); + } + + + /** + * @param array{?id: int, ?collection: string, ?model: string} $modelParam + */ + public static function getModel($modelParam): HasMedia + { + $model = app('media-library-helpers')->get($modelParam['model']); + + return $model::find($modelParam['id']); + } + + /** + * @param array{?id: int, ?collection: string, ?model: string} $modelParam + */ + public static function getCollection($modelParam): MediaCollection + { + return static::getModel($modelParam)->getMediaCollection($modelParam['collection']); + } +} diff --git a/tests/Feature/UploadTest.php b/tests/Feature/UploadTest.php index bcb3088..7c30723 100644 --- a/tests/Feature/UploadTest.php +++ b/tests/Feature/UploadTest.php @@ -13,9 +13,7 @@ test('it uploads a single file to a single file collection', function () { $content = base64_encode($this->pdfFile()->getContent()); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'defaultSingleFile', + 'parent' => ['model' => 'post', 'collection' => 'defaultSingleFile', 'id' => $post->id], 'payload' => [ 'content' => $content, 'name' => 'beispiel bild.jpg', @@ -35,88 +33,13 @@ test('it uploads a single file to a single file collection', function () { $response->assertJsonMissingPath('model_id'); }); -test('test validation', function (array $attributes, string $messages) { - $this->auth()->registerModel(); - $post = $this->newPost(); - $content = base64_encode($this->pdfFile()->getContent()); - - $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'defaultSingleFile', - 'payload' => [ - 'content' => $content, - 'name' => 'beispiel bild.jpg', - ], - ...$attributes - ])->assertJsonValidationErrors($messages); -})->with([ - 'missing collection' => [ - ['collection' => ''], - 'collection' - ], - 'missing id' => [ - ['id' => ''], - 'id' - ], -]); - -test('test validation for payload', function () { - $this->auth()->registerModel(); - $post = $this->newPost(); - - $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'defaultSingleFile', - 'payload' => [ - 'content' => '', - 'name' => 'beispiel bild.jpg', - ], - ])->assertJsonValidationErrors('payload.content'); -}); - -test('test validation for name', function () { - $this->auth()->registerModel(); - $post = $this->newPost(); - $content = base64_encode($this->pdfFile()->getContent()); - - $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'defaultSingleFile', - 'payload' => [ - 'content' => $content, - 'name' => '', - ], - ])->assertJsonValidationErrors('payload.name'); -}); - -test('test validation for extension', function () { - $this->auth()->registerModel(); - $post = $this->newPost(); - $content = base64_encode($this->pdfFile()->getContent()); - - $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'defaultSingleFile', - 'payload' => [ - 'content' => $content, - 'name' => 'aaa', - ], - ])->assertJsonValidationErrors('payload.name'); -}); - test('it uploads a single image to a single file collection', function () { $this->auth()->registerModel(); $post = $this->newPost(); $content = base64_encode($this->jpgFile()->getContent()); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'defaultSingleFile', + 'parent' => ['model' => 'post', 'collection' => 'defaultSingleFile', 'id' => $post->id], 'payload' => [ 'content' => $content, 'name' => 'beispiel bild.jpg', @@ -134,9 +57,7 @@ test('it forces a filename for a single collection', function () { $content = base64_encode($this->pdfFile()->getContent()); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'singleForced', + 'parent' => ['model' => 'post', 'collection' => 'singleForced', 'id' => $post->id], 'payload' => [ 'content' => $content, 'name' => 'beispiel bild.jpg', @@ -155,9 +76,7 @@ test('it sets custom title when storing', function () { $content = base64_encode($this->pdfFile()->getContent()); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'singleStoringHook', + 'parent' => ['model' => 'post', 'collection' => 'singleStoringHook', 'id' => $post->id], 'payload' => [ 'content' => $content, 'name' => 'beispiel bild.jpg', @@ -177,9 +96,7 @@ test('it sets custom properties from properties method', function () { $content = base64_encode($this->pdfFile()->getContent()); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'multipleProperties', + 'parent' => ['model' => 'post', 'collection' => 'multipleProperties', 'id' => $post->id], 'payload' => [ 'content' => $content, 'name' => 'beispiel bild.jpg', @@ -199,9 +116,7 @@ test('it forces a filename for multiple collections', function () { $content = base64_encode($this->pdfFile()->getContent()); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'multipleForced', + 'parent' => ['model' => 'post', 'collection' => 'multipleForced', 'id' => $post->id], 'payload' => [ [ 'content' => $content, @@ -222,9 +137,7 @@ test('it throws event when file has been uploaded', function () { $content = base64_encode($this->pdfFile()->getContent()); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'singleWithEvent', + 'parent' => ['model' => 'post', 'collection' => 'singleWithEvent', 'id' => $post->id], 'payload' => [ 'content' => $content, 'name' => 'beispiel bild.jpg', @@ -244,9 +157,7 @@ test('it throws event when multiple files uploaded', function () { $content = base64_encode($this->pdfFile()->getContent()); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'multipleFilesWithEvent', + 'parent' => ['model' => 'post', 'collection' => 'multipleFilesWithEvent', 'id' => $post->id], 'payload' => [ [ 'content' => $content, @@ -271,9 +182,7 @@ test('it uploads multiple files', function () { $post->addMedia($file->getPathname())->preservingOriginal()->toMediaCollection('images'); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'images', + 'parent' => ['model' => 'post', 'collection' => 'images', 'id' => $post->id], 'payload' => [ [ 'content' => base64_encode($file->getContent()), @@ -306,9 +215,7 @@ test('it returns 403 when not authorized', function () { $post = $this->newPost(); $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'defaultSingleFile', + 'parent' => ['model' => 'post', 'collection' => 'defaultSingleFile', 'id' => $post->id], 'payload' => [ 'content' => base64_encode($this->pdfFile()->getContent()), 'name' => 'beispiel bild.jpg', @@ -318,63 +225,71 @@ test('it returns 403 when not authorized', function () { $response->assertStatus(403); }); -test('it needs validation for single files', function (array $payload, string $invalidFieldName) { +test('it needs validation for single files', function (array $payloadOverwrites, string $invalidFieldName) { $this->auth()->registerModel(); $post = $this->newPost(); - $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'defaultSingleFile', + $payload = [ + 'parent' => ['model' => 'post', 'collection' => 'defaultSingleFile', 'id' => $post->id], 'payload' => [ 'content' => base64_encode($this->pdfFile()->getContent()), 'name' => 'beispiel bild.jpg', ], - ...$payload, - ]); + ]; + + foreach ($payloadOverwrites as $key => $value) { + data_set($payload, $key, $value); + } + + $response = $this->postJson('/mediaupload', $payload); $response->assertStatus(422); $response->assertJsonValidationErrors($invalidFieldName); })->with(function () { - yield [['model' => 'missingmodel'], 'model']; - yield [['id' => -1], 'model']; - yield [['collection' => 'missingcollection'], 'collection']; - yield [['payload' => ['name' => 'AAA', 'content' => []]], 'payload.content']; - yield [['payload' => ['name' => 'AAA', 'content' => ['UU']]], 'payload.content']; - yield [['payload' => ['name' => 'AAA', 'content' => null]], 'payload.content']; - yield [['payload' => ['name' => 'AAA', 'content' => '']], 'payload.content']; - yield [['payload' => ['name' => 'AAA', 'content' => 1]], 'payload.content']; - yield [['payload' => ['name' => '', 'content' => 'aaadfdf']], 'payload.name']; - yield [['payload' => ['name' => ['U'], 'content' => 'aaadfdf']], 'payload.name']; - yield [['payload' => ['name' => 1, 'content' => 'aaadfdf']], 'payload.name']; - yield [['payload' => ['name' => null, 'content' => 'aaadfdf']], 'payload.name']; + yield [['parent.model' => 'missingmodel'], 'parent.model']; + yield [['parent.id' => -1], 'parent.id']; + yield [['parent.id' => ''], 'parent.id']; + yield [['parent.collection' => 'missingcollection'], 'parent.collection']; + yield [['payload.content' => []], 'payload.content']; + yield [['payload.content' => ['UU']], 'payload.content']; + yield [['payload.content' => null], 'payload.content']; + yield [['payload.content' => ''], 'payload.content']; + yield [['payload.content' => 1], 'payload.content']; + yield [['payload.name' => ''], 'payload.name']; + yield [['payload.name' => ['U']], 'payload.name']; + yield [['payload.name' => 1], 'payload.name']; + yield [['payload.name' => null], 'payload.name']; yield [['payload' => 'lalal'], 'payload']; yield [['payload' => 55], 'payload']; }); -test('it needs validation for multiple files', function (array $payload, string $invalidFieldName) { +test('it needs validation for multiple files', function (array $payloadOverwrites, string $invalidFieldName) { $this->auth()->registerModel(); $post = $this->newPost(); - $response = $this->postJson('/mediaupload', [ - 'model' => 'post', - 'id' => $post->id, - 'collection' => 'images', + $payload = [ + 'parent' => ['model' => 'post', 'collection' => 'images', 'id' => $post->id], 'payload' => [ [ 'content' => base64_encode($this->pdfFile()->getContent()), 'name' => 'beispiel bild.jpg', ], ], - ...$payload, - ]); + ]; + + foreach ($payloadOverwrites as $key => $value) { + data_set($payload, $key, $value); + } + + $response = $this->postJson('/mediaupload', $payload); + $response->assertStatus(422); $response->assertJsonValidationErrors($invalidFieldName); })->with(function () { - yield [['model' => 'missingmodel'], 'model']; - yield [['id' => -1], 'model']; - yield [['collection' => 'missingcollection'], 'collection']; + yield [['parent.model' => 'missingmodel'], 'parent.model']; + yield [['parent.model' => 'post.missingcollection'], 'parent.model']; + yield [['parent.id' => -1], 'parent.id']; yield [['payload' => 'lalal'], 'payload']; yield [['payload' => []], 'payload']; yield [['payload' => 1], 'payload'];