Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions app/Http/Requests/Concerns/HasImageUploads.php
Original file line number Diff line number Diff line change
Expand Up @@ -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: $this->maxFilenameLength()),
];
}

public function uploadedImageMessages(string $rule): string
Expand All @@ -31,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
*
Expand Down Expand Up @@ -83,4 +95,9 @@ public function supportedMimes(): array
return $mimes;
}

public function supportedMimeString(): string
{
return implode(', ', $this->supportedMimes());
}

}
25 changes: 25 additions & 0 deletions app/Rules/FilenameLengthRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Http\UploadedFile;

class FilenameLengthRule implements ValidationRule
{
public function __construct(private int $maxLength = 100) {}

public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (! $value instanceof UploadedFile) {
return;
}

$name = $value->getClientOriginalName();

if (mb_strlen($name) > $this->maxLength) {
$fail("The :attribute filename must not exceed {$this->maxLength} characters.");
}
}
}
5 changes: 5 additions & 0 deletions config/media-library.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 15 additions & 6 deletions public/js/app.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions public/mix-manifest.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
6 changes: 6 additions & 0 deletions resources/assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Expand Down
8 changes: 8 additions & 0 deletions resources/views/profiles/edit/_img_rules.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@php
$img_request = new \App\Http\Requests\ProfileImageRequest();
@endphp
<div id="img-rules" style="display:none">
<p class="m-1"><small>Supported file types: {{ $img_request->supportedMimeString() }}.</small></p>
<p class="m-1"><small>Maximum file size: {{ $img_request->maxFilesize() }} MB.</small></p>
<p class="m-1"><small>Maximum file name length: {{ $img_request->maxFilenameLength() }} characters.</small></p>
</div>
3 changes: 3 additions & 0 deletions resources/views/profiles/edit/information.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<label for="file">Icon</label>
<img id="file-img" class="profile_photo" src="{{ $profile->imageUrl }}" />
<br />
<small class="form-text text-muted"> Image requirements <a role="button" tabindex="0" aria-label="image requirements information" data-toggle="popover" data-trigger="focus" data-popover-content="#img-rules"><i class="fas fa-question-circle"></i></a></small>
@include('profiles.edit._img_rules')
<br />
<div class="control-group">
<div class="controls">
Expand All @@ -24,6 +26,7 @@
<label for="banner">Banner</label>
<img id="banner-img" class="profile_photo" src="{{ $profile->banner_url }}" />
<br />
<small class="form-text text-muted"> Image requirements <a role="button" tabindex="0" aria-label="image requirements information" data-toggle="popover" data-trigger="focus" data-popover-content="#img-rules"><i class="fas fa-question-circle"></i></a></small>
<br />
<div class="control-group">
<div class="controls">
Expand Down
4 changes: 3 additions & 1 deletion resources/views/profiles/edit/news.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@
<label for="data[{{ $news->id }}][image]-img">Image</label>
<img class="uploaded-image w-100 d-flex" id="data[{{ $news->id }}][image]-img"
src="@if ($news->imageUrl != asset('/img/default.png')) {{ $news->imageUrl }} @endif">
<div class="custom-file form-control">
<div class="custom-file form-control" style="margin-bottom: 0px!important;">
<input type="file" id="data[{{ $news->id }}][image]" name="data[{{ $news->id }}][image]"
accept="image/*" class="custom-file-input clickable">
<label id="label-{{ $news->id }}" for="data[{{ $news->id }}][image]"
class="custom-file-label">
{{ $news->image->file_name ?? 'Select an image' }}
</label>
</div>
<small class="form-text text-muted"> Image requirements <a role="button" tabindex="0" aria-label="image requirements information" data-toggle="popover" data-trigger="focus" data-popover-content="#img-rules"><i class="fas fa-question-circle"></i></a></small>
@foreach ($errors->get("data.{$news->id}.image") as $image_error)
@include('alert', ['message' => $image_error, 'type' => 'danger'])
<p class="d-block invalid-feedback"><i class="fas fa-asterisk"></i> {!! $image_error !!}</p>
Expand All @@ -57,4 +58,5 @@ class="custom-file-label">
</div>
</div>
@endforeach
@include('profiles.edit._img_rules')
@endsection
Loading