mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-24 18:00:40 +00:00
Generate multiple avatar sizes for better performance loading and frugal traffic
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
namespace Domain\Files\Actions;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Intervention\Image\ImageManagerStatic as Image;
|
||||
|
||||
class CreateImageThumbnailAction
|
||||
@@ -18,34 +19,31 @@ class CreateImageThumbnailAction
|
||||
* Create image thumbnail from uploaded image
|
||||
*/
|
||||
public function __invoke(
|
||||
string $file_path,
|
||||
string $filename,
|
||||
string $file_name,
|
||||
$file,
|
||||
string $user_id
|
||||
): string | null {
|
||||
$mimeType = Storage::disk('local')->mimeType($file_path);
|
||||
): void {
|
||||
|
||||
// Create thumbnail from image
|
||||
if (in_array($mimeType, $this->availableFormats)) {
|
||||
// Get thumbnail name
|
||||
$thumbnail = "thumbnail-$filename";
|
||||
if (in_array($file->getClientMimeType(), $this->availableFormats)) {
|
||||
|
||||
// Create intervention image
|
||||
$image = Image::make(Storage::disk('local')
|
||||
->path($file_path))
|
||||
->orientate();
|
||||
$intervention = Image::make($file)->orientate();
|
||||
|
||||
// Resize image
|
||||
$image->resize(512, null, fn ($constraint) => $constraint->aspectRatio())->stream();
|
||||
// Generate avatar sizes
|
||||
collect(config('vuefilemanager.image_sizes'))
|
||||
->each(function ($size) use ($intervention, $file_name, $user_id) {
|
||||
|
||||
// Store thumbnail to disk
|
||||
Storage::put("files/$user_id/$thumbnail", $image);
|
||||
// Create thumbnail only if image is larger than predefined image sizes
|
||||
if ($intervention->getWidth() > $size['size']) {
|
||||
|
||||
// Generate thumbnail
|
||||
$intervention->resize($size['size'], null, fn ($constraint) => $constraint->aspectRatio())->stream();
|
||||
|
||||
// Store thumbnail to disk
|
||||
Storage::put("files/$user_id/{$size['name']}-{$file_name}", $intervention);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Return thumbnail as svg file
|
||||
if ($mimeType === 'image/svg+xml') {
|
||||
return $filename;
|
||||
}
|
||||
|
||||
return $thumbnail ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,18 +11,28 @@ class DownloadThumbnailAction
|
||||
* Get image thumbnail for browser
|
||||
*/
|
||||
public function __invoke(
|
||||
File $file,
|
||||
string $user_id
|
||||
string $filename,
|
||||
File $file
|
||||
): StreamedResponse {
|
||||
// Get file path
|
||||
$path = "/files/$user_id/{$file->getRawOriginal('thumbnail')}";
|
||||
$path = "/files/$file->user_id/$filename";
|
||||
|
||||
// Check if file exist
|
||||
if (! Storage::exists($path)) {
|
||||
abort(404);
|
||||
|
||||
// Get original file path
|
||||
$substituteFilePath = "/files/$file->user_id/$file->basename";
|
||||
|
||||
// Check if original file exist
|
||||
if (! Storage::exists($substituteFilePath)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
// Return image thumbnail
|
||||
return Storage::download($substituteFilePath, $filename);
|
||||
}
|
||||
|
||||
// Return image thumbnail
|
||||
return Storage::download($path, $file->getRawOriginal('thumbnail'));
|
||||
return Storage::download($path, $filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use Domain\Files\Requests\UploadRequest;
|
||||
use Domain\Files\Models\File as UserFile;
|
||||
use Domain\Traffic\Actions\RecordUploadAction;
|
||||
use App\Users\Actions\CheckStorageCapacityAction;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class UploadFileAction
|
||||
{
|
||||
@@ -27,27 +28,27 @@ class UploadFileAction
|
||||
UploadRequest $request,
|
||||
?Share $shared = null,
|
||||
) {
|
||||
// Get parent_id from request
|
||||
$file = $request->file('file');
|
||||
|
||||
$chunkName = $file->getClientOriginalName();
|
||||
|
||||
// File name
|
||||
$disk_file_name = basename('chunks/' . $file->getClientOriginalName(), '.part');
|
||||
$temp_filename = $file->getClientOriginalName();
|
||||
$fileName = Str::uuid() . '.' . $file->extension();
|
||||
|
||||
// File Path
|
||||
$file_path = Storage::disk('local')->path('chunks/' . $temp_filename);
|
||||
$filePath = Storage::disk('local')->path('chunks/' . $chunkName);
|
||||
|
||||
// Generate file
|
||||
File::append($file_path, $file->get());
|
||||
File::append($filePath, $file->get());
|
||||
|
||||
// Size of file
|
||||
$file_size = File::size($file_path);
|
||||
$fileSize = File::size($filePath);
|
||||
|
||||
// Size of limit
|
||||
$limit = get_settings('upload_limit');
|
||||
$uploadLimit = get_settings('upload_limit');
|
||||
|
||||
// File size handling
|
||||
if ($limit && $file_size > format_bytes($limit)) {
|
||||
if ($uploadLimit && $fileSize > format_bytes($uploadLimit)) {
|
||||
abort(413);
|
||||
}
|
||||
|
||||
@@ -61,26 +62,26 @@ class UploadFileAction
|
||||
$user_id = $shared->user_id ?? Auth::id();
|
||||
|
||||
// File Info
|
||||
$file_size = $disk_local->size("chunks/$temp_filename");
|
||||
$fileSize = $disk_local->size("chunks/$chunkName");
|
||||
|
||||
$file_mimetype = $disk_local->mimeType("chunks/$temp_filename");
|
||||
$file_mimetype = $disk_local->mimeType("chunks/$chunkName");
|
||||
|
||||
// Check if user has enough space to upload file
|
||||
($this->checkStorageCapacity)($user_id, $file_size, $temp_filename);
|
||||
($this->checkStorageCapacity)($user_id, $fileSize, $chunkName);
|
||||
|
||||
// Create thumbnail
|
||||
$thumbnail = ($this->createImageThumbnail)("chunks/$temp_filename", $disk_file_name, $user_id);
|
||||
// Create multiple image thumbnails
|
||||
($this->createImageThumbnail)($fileName, $file, $user_id);
|
||||
|
||||
// Move finished file from chunk to file-manager directory
|
||||
$disk_local->move("chunks/$temp_filename", "files/$user_id/$disk_file_name");
|
||||
$disk_local->move("chunks/$chunkName", "files/$user_id/$fileName");
|
||||
|
||||
// Move files to external storage
|
||||
if (! is_storage_driver(['local'])) {
|
||||
($this->moveFileToExternalStorage)($disk_file_name, $user_id);
|
||||
($this->moveFileToExternalStorage)($fileName, $user_id);
|
||||
}
|
||||
|
||||
// Store user upload size
|
||||
($this->recordUpload)($file_size, $user_id);
|
||||
($this->recordUpload)($fileSize, $user_id);
|
||||
|
||||
// Return new file
|
||||
return UserFile::create([
|
||||
@@ -89,10 +90,9 @@ class UploadFileAction
|
||||
'parent_id' => $request->input('parent_id'),
|
||||
'metadata' => $metadata,
|
||||
'name' => $request->input('filename'),
|
||||
'basename' => $disk_file_name,
|
||||
'basename' => $fileName,
|
||||
'author' => $shared ? 'visitor' : 'user',
|
||||
'thumbnail' => $thumbnail,
|
||||
'filesize' => $file_size,
|
||||
'filesize' => $fileSize,
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ namespace Domain\Files\Controllers\FileAccess;
|
||||
|
||||
use Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use Domain\Files\Models\File;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Files\Models\File as UserFile;
|
||||
use Domain\Files\Actions\DownloadThumbnailAction;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
@@ -20,14 +20,16 @@ class GetThumbnailController extends Controller
|
||||
string $filename,
|
||||
): FileNotFoundException | StreamedResponse {
|
||||
|
||||
$file = UserFile::withTrashed()
|
||||
->where('thumbnail', $filename)
|
||||
$originalFileName = substr($filename, 3);
|
||||
|
||||
$file = File::withTrashed()
|
||||
->where('basename', $originalFileName)
|
||||
->firstOrFail();
|
||||
|
||||
if (! Gate::any(['can-edit', 'can-view'], [$file, null])) {
|
||||
abort(403, 'Access Denied');
|
||||
}
|
||||
|
||||
return ($this->downloadThumbnail)($file, $file->user_id);
|
||||
return ($this->downloadThumbnail)($filename, $file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,11 @@ class VisitorGetThumbnailController extends Controller
|
||||
// Check ability to access protected share files
|
||||
($this->protectShareRecord)($shared);
|
||||
|
||||
$originalFileName = substr($filename, 3);
|
||||
|
||||
// Get file record
|
||||
$file = UserFile::where('user_id', $shared->user_id)
|
||||
->where('thumbnail', $filename)
|
||||
->where('basename', $originalFileName)
|
||||
->firstOrFail();
|
||||
|
||||
// Check file access
|
||||
@@ -44,7 +46,7 @@ class VisitorGetThumbnailController extends Controller
|
||||
user_id: $shared->user_id,
|
||||
);
|
||||
|
||||
// Finally download thumbnail
|
||||
return ($this->downloadThumbnail)($file, $shared->user_id);
|
||||
// Finally, download thumbnail
|
||||
return ($this->downloadThumbnail)($filename, $file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
* @property string name
|
||||
* @property string mimetype
|
||||
* @property string author
|
||||
* @property string author_id
|
||||
* @property string created_at
|
||||
* @property string updated_at
|
||||
* @property string deleted_at
|
||||
@@ -51,6 +50,7 @@ class File extends Model
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
'thumbnail',
|
||||
'file_url',
|
||||
];
|
||||
|
||||
@@ -58,10 +58,6 @@ class File extends Model
|
||||
'metadata' => 'array',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'author_id',
|
||||
];
|
||||
|
||||
public array $sortable = [
|
||||
'name',
|
||||
'created_at',
|
||||
@@ -92,23 +88,38 @@ class File extends Model
|
||||
/**
|
||||
* Format thumbnail url
|
||||
*/
|
||||
public function getThumbnailAttribute(): string | null
|
||||
public function getThumbnailAttribute(): array | null
|
||||
{
|
||||
// Get thumbnail from external storage
|
||||
if ($this->attributes['thumbnail'] && ! is_storage_driver(['local'])) {
|
||||
return Storage::temporaryUrl("files/$this->user_id/{$this->attributes['thumbnail']}", now()->addHour());
|
||||
}
|
||||
$links = [];
|
||||
|
||||
// Get thumbnail from local storage
|
||||
if ($this->attributes['thumbnail']) {
|
||||
// Thumbnail route
|
||||
$route = route('thumbnail', ['name' => $this->attributes['thumbnail']]);
|
||||
// Generate thumbnail link for external storage service
|
||||
if ($this->type === 'image' && ! is_storage_driver(['local'])) {
|
||||
|
||||
if ($this->public_access) {
|
||||
return "$route/$this->public_access";
|
||||
foreach (config('vuefilemanager.image_sizes') as $item) {
|
||||
|
||||
$filePath = "files/{$this->user_id}/{$item['name']}-{$this->basename}";
|
||||
|
||||
$links[$item['name']] = Storage::temporaryUrl($filePath, now()->addHour());
|
||||
}
|
||||
|
||||
return $route;
|
||||
return $links;
|
||||
}
|
||||
|
||||
// Generate thumbnail link for local storage
|
||||
if ($this->type === 'image') {
|
||||
|
||||
foreach (config('vuefilemanager.image_sizes') as $item) {
|
||||
|
||||
$route = route('thumbnail', ['name' => $item['name'] . '-' . $this->basename]);
|
||||
|
||||
if ($this->public_access) {
|
||||
$route .= "/$this->public_access";
|
||||
}
|
||||
|
||||
$links[$item['name']] = $route;
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user