Skip to content

Commit

Permalink
[5.x] Add validation to asset containers (#10227)
Browse files Browse the repository at this point in the history
Co-authored-by: Jason Varga <[email protected]>
  • Loading branch information
edalzell and jasonvarga authored Jun 4, 2024
1 parent 588a1ed commit ab0084d
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 6 deletions.
6 changes: 5 additions & 1 deletion resources/js/components/assets/Uploader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export default {
response.status === 200
? this.handleUploadSuccess(id, json)
: this.handleUploadError(id, status, json);
: this.handleUploadError(id, response.status, json);
});
},
Expand All @@ -204,6 +204,10 @@ export default {
} else {
msg = __('Upload failed. The file might be larger than is allowed by your server.');
}
} else {
if (status === 422) {
msg = Object.values(response.errors)[0][0]; // Get first validation message.
}
}
upload.errorMessage = msg;
this.$emit('error', upload, this.uploads);
Expand Down
1 change: 1 addition & 0 deletions resources/lang/en/messages.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
'asset_container_title_instructions' => 'Usually a plural noun, like Images or Documents',
'asset_container_warm_intelligent_instructions' => 'Generate appropriate presets on upload.',
'asset_container_warm_presets_instructions' => 'Specify which presets to generate on upload.',
'asset_container_validation_rules_instructions' => 'These rules will be applied to uploaded files.',
'asset_folders_directory_instructions' => 'We recommend avoiding spaces and special characters to keep URLs clean.',
'asset_replace_confirmation' => 'References to this asset within content will be updated to the asset you select below.',
'asset_reupload_confirmation' => 'Are you sure you want to reupload this asset?',
Expand Down
16 changes: 16 additions & 0 deletions src/Assets/AssetContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class AssetContainer implements Arrayable, ArrayAccess, AssetContainerContract,
protected $withEvents = true;
protected $sortField;
protected $sortDirection;
protected $validation;

public function id($id = null)
{
Expand Down Expand Up @@ -99,6 +100,20 @@ public function title($title = null)
->args(func_get_args());
}

/**
* Get or set the validation rules.
*
* @param null|array $rules
* @return array
*/
public function validationRules($rules = null)
{
return $this
->fluentlyGetOrSet('validation')
->getter(fn ($rules) => $rules ?? [])
->args(func_get_args());
}

public function diskPath()
{
return rtrim($this->disk()->path('/'), '/');
Expand Down Expand Up @@ -625,6 +640,7 @@ public function fileData()
'create_folders' => $this->createFolders,
'source_preset' => $this->sourcePreset,
'warm_presets' => $this->warmPresets,
'validate' => $this->validation,
];

$array = Arr::removeNullValues(array_merge($array, [
Expand Down
8 changes: 8 additions & 0 deletions src/Contracts/Assets/AssetContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,12 @@ public function accessible();
* @return bool
*/
public function private();

/**
* Get or set the validation rules.
*
* @param null|array $rules
* @return array
*/
// public function validationRules($rules = null);
}
9 changes: 8 additions & 1 deletion src/Http/Controllers/CP/Assets/AssetContainersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public function edit($container)
'source_preset' => $container->sourcePreset(),
'warm_intelligent' => $intelligent = $container->warmsPresetsIntelligently(),
'warm_presets' => $intelligent ? [] : $container->warmPresets(),
'validation' => $container->validationRules(),
];

$fields = ($blueprint = $this->formBlueprint($container))
Expand Down Expand Up @@ -99,7 +100,8 @@ public function update(Request $request, $container)
->allowUploads($values['allow_uploads'])
->createFolders($values['create_folders'])
->sourcePreset($values['source_preset'])
->warmPresets($values['warm_intelligent'] ? null : $values['warm_presets']);
->warmPresets($values['warm_intelligent'] ? null : $values['warm_presets'])
->validationRules($values['validation'] ?? null);

$container->save();

Expand Down Expand Up @@ -265,6 +267,11 @@ protected function formBlueprint($container = null)
'instructions' => __('statamic::messages.asset_container_quick_download_instructions'),
'default' => true,
],
'validation' => [
'type' => 'taggable',
'display' => __('Validation Rules'),
'instructions' => __('statamic::messages.asset_container_validation_rules_instructions'),
],
],
],
]);
Expand Down
6 changes: 4 additions & 2 deletions src/Http/Controllers/CP/Assets/AssetsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@ public function store(Request $request)
$request->validate([
'container' => 'required',
'folder' => 'required',
'file' => ['file', new AllowedFile],
]);

$container = AssetContainer::find($request->container);

abort_unless($container->allowUploads(), 403);

$this->authorize('store', [AssetContract::class, $container]);

$request->validate([
'file' => array_merge(['file', new AllowedFile], $container->validationRules()),
]);

$file = $request->file('file');
$path = ltrim($request->folder.'/'.$file->getClientOriginalName(), '/');

Expand Down
3 changes: 2 additions & 1 deletion src/Stache/Stores/AssetContainersStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public function makeItemFromFile($path, $contents)
->warmPresets(Arr::get($data, 'warm_presets'))
->searchIndex(Arr::get($data, 'search_index'))
->sortField(Arr::get($data, 'sort_by'))
->sortDirection(Arr::get($data, 'sort_dir'));
->sortDirection(Arr::get($data, 'sort_dir'))
->validationRules(Arr::get($data, 'validate'));
}
}
12 changes: 12 additions & 0 deletions tests/Assets/AssetContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,18 @@ public function it_gets_and_sets_whether_downloading_is_allowed()
$this->assertFalse($container->allowDownloading());
}

/** @test */
public function it_gets_and_sets_the_validation_rules()
{
$container = new AssetContainer;
$this->assertEmpty($container->validationRules());

$return = $container->validationRules(['max:5120']);

$this->assertEquals($container, $return);
$this->assertEquals(['max:5120'], $container->validationRules());
}

/** @test */
public function it_gets_and_sets_glide_source_preset_for_upload_processing()
{
Expand Down
12 changes: 12 additions & 0 deletions tests/Feature/Assets/StoreAssetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ public function it_doesnt_upload_without_a_folder()
])->assertStatus(422);
}

/** @test */
public function it_doesnt_upload_when_validation_fails()
{

$this->container->validationRules(['extensions:png'])->save();

$this
->actingAs($this->userWithPermission())
->submit()
->assertStatus(422);
}

private function submit($overrides = [])
{
return $this->postJson(cp_route('assets.store'), $this->validPayload($overrides));
Expand Down
5 changes: 4 additions & 1 deletion tests/Stache/Stores/AssetContainersStoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,15 @@ public function it_saves_to_disk()
EOT;
$this->assertStringEqualsFile($this->tempDir.'/new.yaml', $expected);

$container->allowUploads(false)->createFolders(false)->save();
$container->allowUploads(false)->createFolders(false)->validationRules(['max:150', 'mimes:jpg'])->save();

$expected = <<<'EOT'
title: 'New Container'
allow_uploads: false
create_folders: false
validate:
- 'max:150'
- 'mimes:jpg'

EOT;
$this->assertStringEqualsFile($this->tempDir.'/new.yaml', $expected);
Expand Down

0 comments on commit ab0084d

Please sign in to comment.