From 005490b5a0e3c6b50ac8ab9ab790fa5186fcfd4b Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Fri, 15 May 2026 14:50:51 -0500 Subject: [PATCH 1/6] Add filename length validation rule for image uploads --- .../Requests/Concerns/HasImageUploads.php | 11 ++++++-- app/Rules/FilenameLengthRule.php | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 app/Rules/FilenameLengthRule.php diff --git a/app/Http/Requests/Concerns/HasImageUploads.php b/app/Http/Requests/Concerns/HasImageUploads.php index 305dc321..082a2c9b 100644 --- a/app/Http/Requests/Concerns/HasImageUploads.php +++ b/app/Http/Requests/Concerns/HasImageUploads.php @@ -2,14 +2,21 @@ namespace App\Http\Requests\Concerns; +use App\Rules\FilenameLengthRule; + trait HasImageUploads { - public function uploadedImageRules(): string + public function uploadedImageRules(): array { $max_filesize = $this->maxFilesize() * 1000; $allowed_mimes = implode(',', $this->supportedMimes()); - return "mimes:$allowed_mimes|min:1|max:$max_filesize"; + return [ + "mimes:{$allowed_mimes}", + "min:1", + "max:{$max_filesize}", + new FilenameLengthRule(maxLength: 200), + ]; } public function uploadedImageMessages(string $rule): string diff --git a/app/Rules/FilenameLengthRule.php b/app/Rules/FilenameLengthRule.php new file mode 100644 index 00000000..574f309f --- /dev/null +++ b/app/Rules/FilenameLengthRule.php @@ -0,0 +1,25 @@ +getClientOriginalName(); + + if (strlen($name) > $this->maxLength) { + $fail("The :attribute filename must not exceed {$this->maxLength} characters."); + } + } +} \ No newline at end of file From 59082978f2d1e10067fbeb5e1eb31732321c0e76 Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Fri, 15 May 2026 14:51:41 -0500 Subject: [PATCH 2/6] Add image requirements tooltip for profile and banner images --- resources/views/profiles/edit/information.blade.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resources/views/profiles/edit/information.blade.php b/resources/views/profiles/edit/information.blade.php index ba3c214a..6e75afdb 100644 --- a/resources/views/profiles/edit/information.blade.php +++ b/resources/views/profiles/edit/information.blade.php @@ -6,6 +6,12 @@
+ Image requirements +
@@ -24,6 +30,7 @@
+ Image requirements
From ada23650940c1f63c5144bc4127b52db2e4980eb Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Fri, 15 May 2026 15:41:16 -0500 Subject: [PATCH 3/6] Add image uploads requirements to the News section --- resources/views/profiles/edit/news.blade.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/views/profiles/edit/news.blade.php b/resources/views/profiles/edit/news.blade.php index 89595643..5de24f1d 100644 --- a/resources/views/profiles/edit/news.blade.php +++ b/resources/views/profiles/edit/news.blade.php @@ -37,7 +37,7 @@ -
+
+ Image requirements + @foreach ($errors->get("data.{$news->id}.image") as $image_error) @include('alert', ['message' => $image_error, 'type' => 'danger'])

{!! $image_error !!}

From cb50bf3fccb3354279180e00ce1d855a77485d76 Mon Sep 17 00:00:00 2001 From: Wun Chiou Date: Mon, 14 Sep 2026 21:01:24 -0500 Subject: [PATCH 4/6] Image name length: use mb_strlen instead of strlen --- app/Rules/FilenameLengthRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Rules/FilenameLengthRule.php b/app/Rules/FilenameLengthRule.php index 574f309f..d2612985 100644 --- a/app/Rules/FilenameLengthRule.php +++ b/app/Rules/FilenameLengthRule.php @@ -18,7 +18,7 @@ public function validate(string $attribute, mixed $value, Closure $fail): void $name = $value->getClientOriginalName(); - if (strlen($name) > $this->maxLength) { + if (mb_strlen($name) > $this->maxLength) { $fail("The :attribute filename must not exceed {$this->maxLength} characters."); } } From f6b7f85118f7ed32ad53daf493e48009edb2fe2b Mon Sep 17 00:00:00 2001 From: Wun Chiou Date: Mon, 14 Sep 2026 22:43:31 -0500 Subject: [PATCH 5/6] Creates img_rules partial; configurable filename length --- app/Http/Requests/Concerns/HasImageUploads.php | 12 +++++++++++- config/media-library.php | 5 +++++ resources/views/profiles/edit/_img_rules.blade.php | 8 ++++++++ resources/views/profiles/edit/information.blade.php | 6 +----- resources/views/profiles/edit/news.blade.php | 6 +----- 5 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 resources/views/profiles/edit/_img_rules.blade.php diff --git a/app/Http/Requests/Concerns/HasImageUploads.php b/app/Http/Requests/Concerns/HasImageUploads.php index 082a2c9b..a226db0a 100644 --- a/app/Http/Requests/Concerns/HasImageUploads.php +++ b/app/Http/Requests/Concerns/HasImageUploads.php @@ -15,7 +15,7 @@ public function uploadedImageRules(): array "mimes:{$allowed_mimes}", "min:1", "max:{$max_filesize}", - new FilenameLengthRule(maxLength: 200), + new FilenameLengthRule(maxLength: $this->maxFilenameLength()), ]; } @@ -38,6 +38,11 @@ public function maxFilesize() return config('media-library.max_file_size') / (1024 * 1024); } + public function maxFilenameLength(): int + { + return config('media-library.max_filename_length', 200); + } + /** * Determine the supported uploaded image types * @@ -90,4 +95,9 @@ public function supportedMimes(): array return $mimes; } + public function supportedMimeString(): string + { + return implode(', ', $this->supportedMimes()); + } + } diff --git a/config/media-library.php b/config/media-library.php index 495fed7a..bbbd44ba 100644 --- a/config/media-library.php +++ b/config/media-library.php @@ -53,6 +53,11 @@ */ 'max_file_size' => 1024 * 1024 * ((int) env('IMAGE_MAX_MB', 16)), + /** + * The maximum filename character length. (Profiles app specific setting) + */ + 'max_filename_length' => (int) env('IMAGE_MAX_FILENAME_LENGTH', 200), + /* * Uploads whose file name contains any of these extensions will be rejected. * The check looks at every extension in the file name, so a file named diff --git a/resources/views/profiles/edit/_img_rules.blade.php b/resources/views/profiles/edit/_img_rules.blade.php new file mode 100644 index 00000000..772f736e --- /dev/null +++ b/resources/views/profiles/edit/_img_rules.blade.php @@ -0,0 +1,8 @@ +@php +$img_request = new \App\Http\Requests\ProfileImageRequest(); +@endphp + \ No newline at end of file diff --git a/resources/views/profiles/edit/information.blade.php b/resources/views/profiles/edit/information.blade.php index 6e75afdb..6acb5270 100644 --- a/resources/views/profiles/edit/information.blade.php +++ b/resources/views/profiles/edit/information.blade.php @@ -7,11 +7,7 @@
Image requirements - + @include('profiles.edit._img_rules')
diff --git a/resources/views/profiles/edit/news.blade.php b/resources/views/profiles/edit/news.blade.php index 5de24f1d..576207b2 100644 --- a/resources/views/profiles/edit/news.blade.php +++ b/resources/views/profiles/edit/news.blade.php @@ -46,11 +46,6 @@ class="custom-file-label">
Image requirements - @foreach ($errors->get("data.{$news->id}.image") as $image_error) @include('alert', ['message' => $image_error, 'type' => 'danger'])

{!! $image_error !!}

@@ -63,4 +58,5 @@ class="custom-file-label">
@endforeach + @include('profiles.edit._img_rules') @endsection From c9da36c3f352efa9722a0850197d09306ff5d17b Mon Sep 17 00:00:00 2001 From: Wun Chiou Date: Mon, 14 Sep 2026 22:44:49 -0500 Subject: [PATCH 6/6] Fixes popovers within profile editor new rows --- public/js/app.js | 21 +++++++++++++++------ public/mix-manifest.json | 4 ++-- resources/assets/js/app.js | 6 ++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/public/js/app.js b/public/js/app.js index 07d287a3..5d929421 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -194,7 +194,7 @@ var profiles = function ($, undefined) { var item_template = document.querySelector((_options$template = options.template) !== null && _options$template !== void 0 ? _options$template : 'form .record'); var item_container = (_document$querySelect = document.querySelector(options.insertInto)) !== null && _document$querySelect !== void 0 ? _document$querySelect : item_template.parentElement; if (item_template) { - var _new_item$querySelect, _new_item$querySelect2, _new_item$querySelect3, _new_item$querySelect4, _new_item$querySelect5, _new_item$querySelect6, _new_item$querySelect7, _new_item$querySelect8, _new_item$querySelect9, _new_item$querySelect0; + var _new_item$querySelect, _new_item$querySelect2, _new_item$querySelect3, _new_item$querySelect4, _new_item$querySelect5, _new_item$querySelect6, _new_item$querySelect7, _new_item$querySelect8, _new_item$querySelect9, _new_item$querySelect0, _new_item$querySelect1; var old_id = item_template.dataset.rowId; var new_id; if (Number(item_container.dataset.nextRowId) >= 0) { @@ -239,10 +239,19 @@ var profiles = function ($, undefined) { return preview_selected_image(event); }); }); - (_new_item$querySelect9 = new_item.querySelectorAll('.datepicker.year')) === null || _new_item$querySelect9 === void 0 || _new_item$querySelect9.forEach(function (el) { + (_new_item$querySelect9 = new_item.querySelectorAll('[data-toggle="popover"]')) === null || _new_item$querySelect9 === void 0 || _new_item$querySelect9.forEach(function (el) { + $(el).popover({ + html: true, + content: function content() { + var _document$querySelect2, _document$querySelect3; + return (_document$querySelect2 = (_document$querySelect3 = document.querySelector(el.dataset.popoverContent)) === null || _document$querySelect3 === void 0 ? void 0 : _document$querySelect3.innerHTML) !== null && _document$querySelect2 !== void 0 ? _document$querySelect2 : ''; + } + }); + }); + (_new_item$querySelect0 = new_item.querySelectorAll('.datepicker.year')) === null || _new_item$querySelect0 === void 0 || _new_item$querySelect0.forEach(function (el) { $(el).datepicker(config.datepicker.year); }); - (_new_item$querySelect0 = new_item.querySelectorAll('.datepicker.month')) === null || _new_item$querySelect0 === void 0 || _new_item$querySelect0.forEach(function (el) { + (_new_item$querySelect1 = new_item.querySelectorAll('.datepicker.month')) === null || _new_item$querySelect1 === void 0 || _new_item$querySelect1.forEach(function (el) { $(el).datepicker(config.datepicker.month); }); $(new_item).hide(); @@ -705,9 +714,9 @@ $(function () { // Trix editor settings if ((typeof Trix === "undefined" ? "undefined" : _typeof(Trix)) === 'object') { document.addEventListener('trix-initialize', function (e) { - var _document$querySelect2, _document$querySelect3; - (_document$querySelect2 = document.querySelector('trix-toolbar .trix-button-group--history-tools')) === null || _document$querySelect2 === void 0 || _document$querySelect2.remove(); - (_document$querySelect3 = document.querySelector('trix-toolbar .trix-button-group--file-tools')) === null || _document$querySelect3 === void 0 || _document$querySelect3.remove(); + var _document$querySelect4, _document$querySelect5; + (_document$querySelect4 = document.querySelector('trix-toolbar .trix-button-group--history-tools')) === null || _document$querySelect4 === void 0 || _document$querySelect4.remove(); + (_document$querySelect5 = document.querySelector('trix-toolbar .trix-button-group--file-tools')) === null || _document$querySelect5 === void 0 || _document$querySelect5.remove(); }); document.addEventListener('trix-file-accept', function (e) { e.preventDefault(); diff --git a/public/mix-manifest.json b/public/mix-manifest.json index dcb76aea..9fbf1ff4 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -1,6 +1,6 @@ { - "/js/app.js": "/js/app.js?id=d53948d8ce9ce761bd7ca1001d67e004", - "/js/app.js.map": "/js/app.js.map?id=271c8f103c569b8f5613b8778d48ee75", + "/js/app.js": "/js/app.js?id=6c1d77ea43cfb678cb0d6efd90432a64", + "/js/app.js.map": "/js/app.js.map?id=e46a550153ed34ce1a618062fa1a6070", "/js/manifest.js": "/js/manifest.js?id=dc9ead3d7857b522d7de22d75063453c", "/js/manifest.js.map": "/js/manifest.js.map?id=389e00e7d7680b68d4e1d128ce27ff48", "/css/app.css": "/css/app.css?id=0fd161f323dd5c77642c3240bbb47d16", diff --git a/resources/assets/js/app.js b/resources/assets/js/app.js index 6c13e022..7d46d382 100644 --- a/resources/assets/js/app.js +++ b/resources/assets/js/app.js @@ -187,6 +187,12 @@ var profiles = (function ($, undefined) { new_item.querySelectorAll('input[type="file"][accept^="image"]')?.forEach((el) => { $(el).on('change', (event) => preview_selected_image(event)); }); + new_item.querySelectorAll('[data-toggle="popover"]')?.forEach((el) => { + $(el).popover({ + html: true, + content: () => document.querySelector(el.dataset.popoverContent)?.innerHTML ?? '', + }); + }); new_item.querySelectorAll('.datepicker.year')?.forEach((el) => { $(el).datepicker(config.datepicker.year); });