Generate multiple avatar sizes for better performance loading and frugal traffic

This commit is contained in:
Čarodej
2021-11-03 16:28:14 +01:00
parent dc8ec5f20b
commit f139dbae08
30 changed files with 280 additions and 152 deletions

View File

@@ -45,6 +45,7 @@ S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=
S3_DEFAULT_REGION=
S3_BUCKET=
S3_URL=
CASHIER_LOGGER=stack
CASHIER_CURRENCY=

6
changelog.md Normal file
View File

@@ -0,0 +1,6 @@
## Version 2.0
#### Release date: 1. January 2022
### File Preview
- Application now generate multiple image sizes for better loading performance and is also frugal to your total data transfer

View File

@@ -6,7 +6,7 @@ return [
'is_demo' => env('APP_DEMO', false),
// Define size of chunk uploaded by MB.
// E.g. integer 128 means chunk size will be 128MB.
// E.g. integer 128 means chunk size will be 128 MB.
'chunk_size' => env('CHUNK_SIZE', '128'),
'colors' => [
@@ -26,5 +26,28 @@ return [
'size' => 42,
'name' => 'xs',
],
],
'image_sizes' => [
[
'size' => 1440,
'name' => 'xl',
],
[
'size' => 960,
'name' => 'lg',
],
[
'size' => 480,
'name' => 'md',
],
[
'size' => 240,
'name' => 'sm',
],
[
'size' => 120,
'name' => 'xs',
],
]
];

View File

@@ -24,7 +24,6 @@ class CreateFileManagerFolders extends Migration
$table->boolean('team_folder')->default(0);
$table->enum('author', ['user', 'member', 'visitor'])->default('user');
$table->uuid('author_id')->nullable();
$table->softDeletes();
$table->timestamps();

View File

@@ -18,7 +18,6 @@ class CreateFileManagerFiles extends Migration
$table->uuid('user_id')->index();
$table->uuid('parent_id')->nullable();
$table->text('thumbnail')->nullable();
$table->text('name');
$table->string('basename')->index();
@@ -29,7 +28,6 @@ class CreateFileManagerFiles extends Migration
$table->longText('metadata')->nullable();
$table->enum('author', ['user', 'member', 'visitor'])->default('user');
$table->uuid('author_id')->nullable();
$table->softDeletes();
$table->timestamps();

View File

@@ -8,11 +8,11 @@
"/chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/~3e4fdd8b.js": "/chunks/admin~chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/~3e4fdd8b.js?id=1d731f1c4a9daecb2a99",
"/chunks/admin~chunks/app-language~chunks/dashboard~chunks/files~chunks/invoices~chunks/my-shared-item~9b68162c.js": "/chunks/admin~chunks/app-language~chunks/dashboard~chunks/files~chunks/invoices~chunks/my-shared-item~9b68162c.js?id=5841d65172536a8a9bdc",
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~673d1ac3.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~673d1ac3.js?id=d00148360f3d89f2791e",
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.js?id=bbbd57ba43e4f381946f",
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.js?id=2b6bed8bd1b30d268e46",
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~1bec6fe4.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~1bec6fe4.js?id=510e6c1b1017a73a40a6",
"/chunks/admin~chunks/platform.js": "/chunks/admin~chunks/platform.js?id=90270d0c5aeb5c50dacf",
"/chunks/admin~chunks/platform~chunks/settings.js": "/chunks/admin~chunks/platform~chunks/settings.js?id=61e970ffb679245686c3",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.js?id=f005b83de750bfec241f",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.js?id=9e3809e5e5d084a64d9b",
"/chunks/app-appearance.js": "/chunks/app-appearance.js?id=66048f6dddf596913bbd",
"/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~605f4c49.js": "/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~605f4c49.js?id=aa284736dda7647d5c9e",
"/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~8cc7d96f.js": "/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~8cc7d96f.js?id=6bd4516589f23ec25ae6",
@@ -39,7 +39,7 @@
"/chunks/email-verified.js": "/chunks/email-verified.js?id=253ce639751cc8799458",
"/chunks/environment-setup.js": "/chunks/environment-setup.js?id=1c1e6a30b129a6bf8258",
"/chunks/files.js": "/chunks/files.js?id=a4f88b13671ef8b37818",
"/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.js": "/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.js?id=d0a2e05e3e243b2e2c4e",
"/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.js": "/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.js?id=64ac90ff8ae7d3ee3ed1",
"/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~34b5eb22.js": "/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~34b5eb22.js?id=2f2e1987e91a74932dcb",
"/chunks/files~chunks/shared-with-me~chunks/shared/files~chunks/team-folders.js": "/chunks/files~chunks/shared-with-me~chunks/shared/files~chunks/team-folders.js?id=4b8864f9265f55f61cf7",
"/chunks/forgotten-password.js": "/chunks/forgotten-password.js?id=8e13225bf4eda83750fc",
@@ -59,7 +59,7 @@
"/chunks/plans.js": "/chunks/plans.js?id=6fca685daa45f22e4c8f",
"/chunks/platform.js": "/chunks/platform.js?id=7e53bcf8da2d3f9ce731",
"/chunks/platform~chunks/settings-subscription~chunks/shared~chunks/user-subscription.js": "/chunks/platform~chunks/settings-subscription~chunks/shared~chunks/user-subscription.js?id=8656b69a97cace919251",
"/chunks/platform~chunks/shared.js": "/chunks/platform~chunks/shared.js?id=e5b1148cd00410564192",
"/chunks/platform~chunks/shared.js": "/chunks/platform~chunks/shared.js?id=1bb410d04a3fb0bdd15c",
"/chunks/profile.js": "/chunks/profile.js?id=022c1617a575d4aab4e1",
"/chunks/profile~chunks/settings-password.js": "/chunks/profile~chunks/settings-password.js?id=58edfb3a35062e1ba4e0",
"/chunks/purchase-code.js": "/chunks/purchase-code.js?id=f8b2619e393a5823bf29",
@@ -577,7 +577,7 @@
"/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.js": "/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.js?id=8b63f1df2980adfabef3",
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.3e07bae3987249743b99.hot-update.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.3e07bae3987249743b99.hot-update.js",
"/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~34b5eb22.3e07bae3987249743b99.hot-update.js": "/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~34b5eb22.3e07bae3987249743b99.hot-update.js",
"/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.js": "/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.js?id=d8ecc7af25c633e36fc7",
"/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.js": "/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.js?id=9a1bb33d3b2a29b1e823",
"/chunks/shared/single-file.3e07bae3987249743b99.hot-update.js": "/chunks/shared/single-file.3e07bae3987249743b99.hot-update.js",
"/chunks/shared/single-file.f6729672ce5f9ec91bba.hot-update.js": "/chunks/shared/single-file.f6729672ce5f9ec91bba.hot-update.js",
"/chunks/shared/single-file.269aae12674c0fa0ba78.hot-update.js": "/chunks/shared/single-file.269aae12674c0fa0ba78.hot-update.js",
@@ -1238,5 +1238,45 @@
"/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.0e3361cf05f5491c3fe4.hot-update.js": "/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.0e3361cf05f5491c3fe4.hot-update.js",
"/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.dbb98b7c9552aee75229.hot-update.js": "/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.dbb98b7c9552aee75229.hot-update.js",
"/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.a46cfa472ddcfedfd1d3.hot-update.js": "/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.a46cfa472ddcfedfd1d3.hot-update.js",
"/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.81dddd2a458fbea706b1.hot-update.js": "/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.81dddd2a458fbea706b1.hot-update.js"
"/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.81dddd2a458fbea706b1.hot-update.js": "/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.81dddd2a458fbea706b1.hot-update.js",
"/js/main.450ee5d4160fe742926f.hot-update.js": "/js/main.450ee5d4160fe742926f.hot-update.js",
"/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.450ee5d4160fe742926f.hot-update.js": "/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.450ee5d4160fe742926f.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings.450ee5d4160fe742926f.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings.450ee5d4160fe742926f.hot-update.js",
"/chunks/dashboard.450ee5d4160fe742926f.hot-update.js": "/chunks/dashboard.450ee5d4160fe742926f.hot-update.js",
"/chunks/invoices.450ee5d4160fe742926f.hot-update.js": "/chunks/invoices.450ee5d4160fe742926f.hot-update.js",
"/chunks/plan-subscribers.450ee5d4160fe742926f.hot-update.js": "/chunks/plan-subscribers.450ee5d4160fe742926f.hot-update.js",
"/chunks/settings.450ee5d4160fe742926f.hot-update.js": "/chunks/settings.450ee5d4160fe742926f.hot-update.js",
"/chunks/sign-in.450ee5d4160fe742926f.hot-update.js": "/chunks/sign-in.450ee5d4160fe742926f.hot-update.js",
"/chunks/user.450ee5d4160fe742926f.hot-update.js": "/chunks/user.450ee5d4160fe742926f.hot-update.js",
"/chunks/users.450ee5d4160fe742926f.hot-update.js": "/chunks/users.450ee5d4160fe742926f.hot-update.js",
"/js/main.2495e7d5acaa3eac8488.hot-update.js": "/js/main.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.2495e7d5acaa3eac8488.hot-update.js": "/chunks/admin~chunks/files~chunks/invitation~chunks/my-shared-items~chunks/platform~chunks/recent-upl~dfa67595.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings.2495e7d5acaa3eac8488.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/dashboard.2495e7d5acaa3eac8488.hot-update.js": "/chunks/dashboard.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/invoices.2495e7d5acaa3eac8488.hot-update.js": "/chunks/invoices.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/plan-subscribers.2495e7d5acaa3eac8488.hot-update.js": "/chunks/plan-subscribers.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/settings.2495e7d5acaa3eac8488.hot-update.js": "/chunks/settings.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/sign-in.2495e7d5acaa3eac8488.hot-update.js": "/chunks/sign-in.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/user.2495e7d5acaa3eac8488.hot-update.js": "/chunks/user.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/users.2495e7d5acaa3eac8488.hot-update.js": "/chunks/users.2495e7d5acaa3eac8488.hot-update.js",
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.f11a07b8849764c5eedc.hot-update.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.f11a07b8849764c5eedc.hot-update.js",
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.e8e9b81138c420a24012.hot-update.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.e8e9b81138c420a24012.hot-update.js",
"/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.2d7de71b3c1aca044af1.hot-update.js": "/chunks/admin~chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/settin~97130d1f.2d7de71b3c1aca044af1.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.fe023d8569c8b026b949.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.fe023d8569c8b026b949.hot-update.js",
"/chunks/platform~chunks/shared.1993afd1dcd40548680b.hot-update.js": "/chunks/platform~chunks/shared.1993afd1dcd40548680b.hot-update.js",
"/chunks/platform~chunks/shared.1e6ffc5b918c1a56f3ec.hot-update.js": "/chunks/platform~chunks/shared.1e6ffc5b918c1a56f3ec.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.092967a951e7e6a3c542.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.092967a951e7e6a3c542.hot-update.js",
"/chunks/platform~chunks/shared.60816a0cfcf68cc1461b.hot-update.js": "/chunks/platform~chunks/shared.60816a0cfcf68cc1461b.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.039e4a39e7f76f7d4273.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.039e4a39e7f76f7d4273.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.d9e64e4e538180f56b76.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.d9e64e4e538180f56b76.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.41cbcd5a4f04c068ca32.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.41cbcd5a4f04c068ca32.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.f1d6aa34837fbd2fd75f.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.f1d6aa34837fbd2fd75f.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.00cda28209c3020457f7.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.00cda28209c3020457f7.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.a6c208d184d7fc1c3274.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.a6c208d184d7fc1c3274.hot-update.js",
"/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.d25142f270ca87de654b.hot-update.js": "/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.d25142f270ca87de654b.hot-update.js",
"/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.72607ccdad32efc80f18.hot-update.js": "/chunks/files~chunks/my-shared-items~chunks/recent-uploads~chunks/shared-with-me~chunks/shared/files~~bf3ddedc.72607ccdad32efc80f18.hot-update.js",
"/chunks/platform~chunks/shared.72607ccdad32efc80f18.hot-update.js": "/chunks/platform~chunks/shared.72607ccdad32efc80f18.hot-update.js",
"/chunks/admin~chunks/platform~chunks/settings~chunks/shared.6f02e7a9087328e90c0e.hot-update.js": "/chunks/admin~chunks/platform~chunks/settings~chunks/shared.6f02e7a9087328e90c0e.hot-update.js",
"/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.35d8fc34bb0909af669a.hot-update.js": "/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.35d8fc34bb0909af669a.hot-update.js",
"/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.adefeadfc7fcc11dc901.hot-update.js": "/chunks/files~chunks/my-shared-items~chunks/platform~chunks/recent-uploads~chunks/shared~chunks/share~c7960950.adefeadfc7fcc11dc901.hot-update.js"
}

View File

@@ -3,7 +3,7 @@
id="printable-file"
class="file"
:class="{'file-shadow': ! $isMobile() }"
:src="file.data.attributes.file_url"
:src="imageSource"
/>
</template>
@@ -13,5 +13,15 @@
props: [
'file'
],
computed: {
imageSource() {
let windowWidth = window.innerWidth
if (windowWidth > 1280)
return this.file.data.attributes.thumbnail.xl
else
return this.file.data.attributes.thumbnail.lg
}
}
}
</script>

View File

@@ -43,7 +43,7 @@
class="absolute -right-3 -bottom-2.5 transform lg:scale-100 scale-75 z-10"
/>
<img class="object-cover w-full h-full rounded-lg shadow-lg" :src="entry.data.attributes.thumbnail" :alt="entry.data.attributes.name" loading="lazy" />
<img class="object-cover w-full h-full rounded-lg shadow-lg" :src="entry.data.attributes.thumbnail.sm" :alt="entry.data.attributes.name" loading="lazy" />
</div>
</div>

View File

@@ -23,7 +23,7 @@
<FileIconThumbnail v-if="isFile || isVideo || (isImage && !entry.data.attributes.thumbnail)" :entry="entry" class="pr-2" />
<!--Image thumbnail-->
<img v-if="isImage && entry.data.attributes.thumbnail" class="w-12 h-12 rounded ml-0.5 object-cover" :src="entry.data.attributes.thumbnail" :alt="entry.data.attributes.name" loading="lazy" />
<img v-if="isImage && entry.data.attributes.thumbnail" class="w-12 h-12 rounded ml-0.5 object-cover" :src="entry.data.attributes.thumbnail.xs" :alt="entry.data.attributes.name" loading="lazy" />
</div>
<!--Item Info-->

View File

@@ -1,6 +1,6 @@
<template>
<div v-if="canBePreview" class="preview">
<img v-if="singleFile.data.type === 'image' && singleFile.data.attributes.thumbnail" :src="singleFile.data.attributes.thumbnail" :alt="singleFile.data.attributes.name" />
<img v-if="singleFile.data.type === 'image' && singleFile.data.attributes.thumbnail" :src="singleFile.data.attributes.thumbnail.md" :alt="singleFile.data.attributes.name" />
<audio v-else-if="singleFile.data.type === 'audio'" :src="singleFile.data.attributes.file_url" controlsList="nodownload" controls></audio>
<video v-else-if="singleFile.data.type === 'video'" controlsList="nodownload" disablePictureInPicture playsinline controls>
<source :src="singleFile.data.attributes.file_url" type="video/mp4">
@@ -25,7 +25,7 @@
return this.singleFile && ! includes([
'folder', 'file'
], this.singleFile.data.type)
}
},
}
}
</script>

View File

@@ -11,7 +11,7 @@
<FontAwesomeIcon v-if="isFile || (isImage && !item.data.attributes.thumbnail)" class="file-icon" :class="{'file-icon-mobile' : $isMobile()}" icon="file"/>
<!--Image thumbnail-->
<img v-if="isImage && item.data.attributes.thumbnail" class="image" :src="item.data.attributes.thumbnail" :alt="item.data.attributes.name"/>
<img v-if="isImage && item.data.attributes.thumbnail" class="image" :src="item.data.attributes.thumbnail.xs"/>
<!--Else show only folder icon-->
<FolderIcon v-if="isFolder" :item="item" :folder-icon="setFolderIcon" location="thumbnail-item" class="folder svg-color-theme" />

View File

@@ -23,7 +23,8 @@
@if(! $metadata['is_protected'])
@if($metadata['thumbnail'])
<meta property="og:image" content="{{ $metadata['thumbnail'] }}">
<meta property="og:image" content="{{ $metadata['thumbnail']['md'] }}">
@endif
<meta property="og:title" content="{{ $metadata['name'] }} ({{ $metadata['size'] }}) | {{ $settings->app_title ?? 'VueFileManager' }}">

View File

@@ -20,16 +20,23 @@ class UserSettings extends Model
*/
public function getAvatarAttribute()
{
$link = [];
// Get avatar from external storage
if ($this->attributes['avatar'] && ! is_storage_driver('local')) {
return Storage::temporaryUrl($this->attributes['avatar'], now()->addDay());
foreach (config('vuefilemanager.avatar_sizes') as $item) {
$filePath = "avatars/{$item['name']}-{$this->attributes['avatar']}";
$link[$item['name']] = Storage::temporaryUrl($filePath, now()->addDay());
}
return $link;
}
// Get avatar from local storage
if ($this->attributes['avatar']) {
$link = [];
foreach (config('vuefilemanager.avatar_sizes') as $item) {
$link[$item['name']] = url("/avatars/{$item['name']}-{$this->attributes['avatar']}");
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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,
]);
}

View File

@@ -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);
}
}

View 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);
}
}

View 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;

View File

@@ -31,7 +31,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
* @property string color
* @property string emoji
* @property string author
* @property string author_id
* @property string created_at
* @property string updated_at
* @property string deleted_at
@@ -58,10 +57,6 @@ class Folder extends Model
'team_folder' => 'boolean',
];
protected $hidden = [
'author_id',
];
public $sortable = [
'name',
'created_at',

View File

@@ -19,7 +19,7 @@ class WebCrawlerOpenGraphController extends Controller
};
// Get file/folder record
$item = ($namespace)::where('user_id', $share->user->id)
$item = ($namespace)::where('user_id', $share->user_id)
->where('id', $share->item_id)
->first();
@@ -31,7 +31,7 @@ class WebCrawlerOpenGraphController extends Controller
->with('settings', get_settings_in_json())
->with('metadata', [
'url' => url('/share', ['token' => $share->token]),
'is_protected' => $share->is_protected,
'is_protected' => (int) $share->is_protected,
'user' => $share->user->settings->name,
'name' => $item->name,
'size' => $share->type === 'folder'

View File

@@ -119,7 +119,6 @@ class UserAccountTest extends TestCase
Storage::disk('local')
->assertExists("avatars/{$size['name']}-{$user->settings->getRawOriginal('avatar')}")
);
}
/**

View File

@@ -236,9 +236,12 @@ class AdminTest extends TestCase
'name' => 'John Doe',
]);
Storage::disk('local')
->assertExists(
User::whereEmail('john@doe.com')->first()->settings->getRawOriginal('avatar')
$avatar = User::whereEmail('john@doe.com')->first()->settings->getRawOriginal('avatar');
collect(config('vuefilemanager.avatar_sizes'))
->each(fn ($size) =>
Storage::disk('local')
->assertExists("avatars/{$size['name']}-{$avatar}")
);
}

View File

@@ -110,12 +110,21 @@ class BrowseTest extends TestCase
],
],
'isMovable' => true,
'isOpen' => true,
],
[
'location' => 'team-folders',
'name' => 'Team Folders',
'folders' => [],
'isMovable' => false,
'isOpen' => false,
],
[
'location' => 'shared-with-me',
'name' => 'Shared With Me',
'folders' => [],
'isMovable' => false,
'isOpen' => false,
],
]);
}

View File

@@ -1,4 +1,5 @@
<?php
namespace Tests\Domain\Files;
use Storage;
@@ -79,20 +80,19 @@ class ContentAccessTest extends TestCase
->create();
$thumbnail = UploadedFile::fake()
->image(Str::random() . '-fake-thumbnail.jpg');
->image('fake-thumbnail.jpg');
Storage::putFileAs("files/$user->id", $thumbnail, $thumbnail->name);
File::factory(File::class)
->create([
'user_id' => $user->id,
'thumbnail' => $thumbnail->name,
'name' => 'fake-thumbnail.jpg',
'user_id' => $user->id,
'basename' => 'fake-thumbnail.jpg',
]);
$this
->actingAs($user)
->get("thumbnail/$thumbnail->name")
->get("thumbnail/xs-$thumbnail->name")
->assertStatus(200);
}
@@ -101,24 +101,23 @@ class ContentAccessTest extends TestCase
*/
public function logged_user_try_to_get_another_private_user_image_thumbnail()
{
$users = User::factory(User::class)
$users = User::factory()
->count(2)
->create();
$thumbnail = UploadedFile::fake()
->image(Str::random() . '-fake-thumbnail.jpg');
->image('fake-thumbnail.jpg', 2000, 2000);
Storage::putFileAs("files/{$users[0]->id}", $thumbnail, $thumbnail->name);
File::factory(File::class)
File::factory()
->create([
'user_id' => $users[0]->id,
'thumbnail' => $thumbnail->name,
'name' => 'fake-thumbnail.jpg',
'user_id' => $users[0]->id,
'basename' => 'fake-thumbnail.jpg',
]);
$this->actingAs($users[1])
->get("thumbnail/$thumbnail->name")
->get("thumbnail/xs-$thumbnail->name")
->assertForbidden();
}

View File

@@ -31,9 +31,9 @@ class FileTest extends TestCase
public function it_upload_image_file_and_create_thumbnail()
{
$file = UploadedFile::fake()
->image('fake-image.jpg');
->image('fake-image.jpg', 2000, 2000);
$user = User::factory(User::class)
$user = User::factory()
->create();
$this
@@ -47,17 +47,18 @@ class FileTest extends TestCase
$disk = Storage::disk('local');
$file = File::first();
$disk->assertMissing(
'chunks/fake-image.jpg'
"chunks/$file->basename"
);
$disk->assertExists(
"files/$user->id/fake-image.jpg"
);
$disk->assertExists(
"files/$user->id/thumbnail-fake-image.jpg"
);
collect(config('vuefilemanager.image_sizes'))
->each(fn ($item) =>
$disk->assertExists(
"files/{$user->id}/{$item['name']}-{$file->basename}"
)
);
}
/**
@@ -82,12 +83,14 @@ class FileTest extends TestCase
$disk = Storage::disk('local');
$file = File::first();
$disk->assertMissing(
'chunks/fake-file.pdf'
"chunks/$file->basename"
);
$disk->assertExists(
"files/$user->id/fake-file.pdf"
"files/$user->id/$file->basename"
);
}

View File

@@ -1,4 +1,5 @@
<?php
namespace Tests\Domain\Homepage;
use Mail;
@@ -83,17 +84,18 @@ class HomepageTest extends TestCase
*/
public function it_get_og_page_for_image()
{
$user = User::factory(User::class)
$user = User::factory()
->create();
$file = File::factory(File::class)
$file = File::factory()
->create([
'user_id' => $user->id,
'name' => 'Fake Image',
'thumbnail' => 'fake-image-thumbnail.jpg',
'user_id' => $user->id,
'name' => 'Fake Image',
'basename' => 'fake-image.jpg',
'type' => 'image',
]);
$share = Share::factory(Share::class)
$share = Share::factory()
->create([
'item_id' => $file->id,
'user_id' => $user->id,
@@ -105,7 +107,7 @@ class HomepageTest extends TestCase
->get("/api/og-site/$share->token")
->assertStatus(200)
->assertSee('Fake Image')
->assertSee('fake-image-thumbnail.jpg');
->assertSee('md-fake-image.jpg');
}
/**
@@ -118,9 +120,10 @@ class HomepageTest extends TestCase
$file = File::factory(File::class)
->create([
'user_id' => $user->id,
'name' => 'Fake Image',
'thumbnail' => 'fake-image-thumbnail.jpg',
'user_id' => $user->id,
'name' => 'Fake Image',
'basename' => 'fake-image.jpg',
'type' => 'image',
]);
$share = Share::factory(Share::class)

View File

@@ -272,7 +272,11 @@ class SetupWizardTest extends TestCase
$this->assertNotNull($avatar);
Storage::assertExists($avatar);
collect(config('vuefilemanager.avatar_sizes'))
->each(fn ($size) =>
Storage::disk('local')
->assertExists("avatars/{$size['name']}-{$avatar}")
);
}
/**

View File

@@ -72,8 +72,8 @@ class VisitorAccessToItemsTest extends TestCase
$file = File::factory(File::class)
->create([
'user_id' => $user->id,
'name' => 'fake-thumbnail.jpg',
'user_id' => $user->id,
'name' => 'fake-thumbnail.jpg',
]);
$share = Share::factory(Share::class)
@@ -99,17 +99,18 @@ class VisitorAccessToItemsTest extends TestCase
$user = User::factory(User::class)
->create();
$thumbnail = UploadedFile::fake()
->image(Str::random() . '-fake-image.jpg');
$fileName = Str::random() . '-fake-image.jpg';
Storage::putFileAs("files/$user->id", $thumbnail, $thumbnail->name);
$thumbnail = UploadedFile::fake()
->image($fileName, 2000, 2000);
Storage::putFileAs("files/$user->id", $thumbnail, $fileName);
$file = File::factory(File::class)
->create([
'user_id' => $user->id,
'thumbnail' => $thumbnail->name,
'basename' => $thumbnail->name,
'name' => 'fake-thumbnail.jpg',
'basename' => $fileName,
'name' => $fileName,
'type' => 'image',
'mimetype' => 'jpg',
]);
@@ -152,16 +153,18 @@ class VisitorAccessToItemsTest extends TestCase
$user = User::factory(User::class)
->create();
$thumbnail = UploadedFile::fake()
->image(Str::random() . '-fake-thumbnail.jpg');
$fileName = Str::random() . '-fake-thumbnail.jpg';
Storage::putFileAs("files/$user->id", $thumbnail, $thumbnail->name);
$thumbnail = UploadedFile::fake()
->image($fileName);
Storage::putFileAs("files/$user->id", $thumbnail, $fileName);
$file = File::factory(File::class)
->create([
'user_id' => $user->id,
'thumbnail' => $thumbnail->name,
'name' => 'fake-thumbnail.jpg',
'user_id' => $user->id,
'name' => $fileName,
'basename' => $fileName,
]);
$share = Share::factory(Share::class)
@@ -182,12 +185,12 @@ class VisitorAccessToItemsTest extends TestCase
];
$this->withCookies($cookie)
->get("/thumbnail/$thumbnail->name/$share->token")
->get("/thumbnail/xs-$fileName/$share->token")
->assertStatus(200);
}
if (!$is_protected) {
$this->get("/thumbnail/$thumbnail->name/$share->token")
$this->get("/thumbnail/xs-$fileName/$share->token")
->assertStatus(200);
}

View File

@@ -348,9 +348,11 @@ class VisitorManipulatingTest extends TestCase
'author' => 'visitor',
]);
$file = File::all()->last();
Storage::disk('local')
->assertExists(
"files/$user->id/fake-file.pdf"
"files/$user->id/$file->basename"
);
});
}