From 54c0bf6f2b5d91cdf67b5a0257b27dbee01ebee7 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Wed, 23 Oct 2024 12:53:39 +0100 Subject: [PATCH] Add `allowed_extensions` option to Files fieldtype --- resources/js/components/assets/Uploader.vue | 30 ++++++++--------- .../components/fieldtypes/FilesFieldtype.vue | 7 ++++ .../Fieldtypes/FilesFieldtypeController.php | 32 ++++++++++++++++++- src/Rules/AllowedFile.php | 9 +++++- 4 files changed, 60 insertions(+), 18 deletions(-) diff --git a/resources/js/components/assets/Uploader.vue b/resources/js/components/assets/Uploader.vue index 7a5439e12d..59798f1888 100644 --- a/resources/js/components/assets/Uploader.vue +++ b/resources/js/components/assets/Uploader.vue @@ -32,7 +32,11 @@ export default { }, container: String, path: String, - url: { type: String, default: () => cp_url('assets') } + url: { type: String, default: () => cp_url('assets') }, + extraData: { + type: Object, + default: () => ({}) + } }, @@ -44,19 +48,6 @@ export default { }, - computed: { - - extraData() { - return { - container: this.container, - folder: this.path, - _token: Statamic.$config.get('csrfToken') - }; - } - - }, - - mounted() { this.$refs.nativeFileField.addEventListener('change', this.addNativeFileFieldSelections); }, @@ -164,8 +155,15 @@ export default { form.append('file', file); - for (let key in this.extraData) { - form.append(key, this.extraData[key]); + let parameters = { + ...this.extraData, + container: this.container, + folder: this.path, + _token: Statamic.$config.get('csrfToken') + } + + for (let key in parameters) { + form.append(key, parameters[key]); } for (let key in data) { diff --git a/resources/js/components/fieldtypes/FilesFieldtype.vue b/resources/js/components/fieldtypes/FilesFieldtype.vue index 1212b41789..81660ec3c0 100644 --- a/resources/js/components/fieldtypes/FilesFieldtype.vue +++ b/resources/js/components/fieldtypes/FilesFieldtype.vue @@ -5,6 +5,7 @@ config ? $this->fieldtype($request) : null; + $request->validate([ - 'file' => ['file', new AllowedFile], + 'file' => ['file', new AllowedFile($fieldtype?->config('allowed_extensions'))], ]); $file = $request->file('file'); @@ -21,4 +25,30 @@ public function upload(Request $request) return ['data' => ['id' => $path]]; } + + protected function fieldtype($request) + { + $config = $this->getConfig($request); + + return Fieldtype::find($config['type'])->setField( + new Field('file', $config) + ); + } + + private function getConfig($request) + { + // The fieldtype base64-encodes the config. + $json = base64_decode($request->config); + + // The json may include unicode characters, so we'll try to convert it to UTF-8. + // See https://github.com/statamic/cms/issues/566 + $utf8 = mb_convert_encoding($json, 'UTF-8', mb_list_encodings()); + + // In PHP 8.1 there's a bug where encoding will return null. It's fixed in 8.1.2. + // In this case, we'll fall back to the original JSON, but without the encoding. + // Issue #566 may still occur, but it's better than failing completely. + $json = empty($utf8) ? $json : $utf8; + + return json_decode($json, true); + } } diff --git a/src/Rules/AllowedFile.php b/src/Rules/AllowedFile.php index 62c71f4c40..6164f9ff48 100644 --- a/src/Rules/AllowedFile.php +++ b/src/Rules/AllowedFile.php @@ -109,6 +109,10 @@ class AllowedFile implements ValidationRule 'zip', ]; + public function __construct(public ?array $allowedExtensions = null) + { + } + public function validate(string $attribute, mixed $value, Closure $fail): void { if (! $this->isAllowedExtension($value)) { @@ -118,7 +122,10 @@ public function validate(string $attribute, mixed $value, Closure $fail): void private function isAllowedExtension(UploadedFile $file): bool { - $extensions = array_merge(static::EXTENSIONS, config('statamic.assets.additional_uploadable_extensions', [])); + $extensions = array_merge( + $this->allowedExtensions ?? static::EXTENSIONS, + config('statamic.assets.additional_uploadable_extensions', []) + ); return in_array(trim(strtolower($file->getClientOriginalExtension())), $extensions); }