feat(profile): add uploadable avatars with local/S3 storage

Users can upload and remove profile pictures on the profile page.
Admins choose local or instance S3 storage in advanced settings.
Avatars are compressed to JPEG and served via a private cached route.
This commit is contained in:
Andras Bacsai committed 2026-08-07 21:39:56 +02:00
1 parent e50108a905
commit 51561e4bee
23 files changed
+677 -44

No files matched your search

+33
View File
@@ -2,15 +2,19 @@
namespace App\Livewire\Profile;
use App\Services\AvatarStorageService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Validation\Rules\Password;
use Livewire\Attributes\Validate;
use Livewire\Component;
use Livewire\WithFileUploads;
class Index extends Component
{
use WithFileUploads;
public int $userId;
public string $email;
@@ -32,6 +36,35 @@ class Index extends Component
public bool $show_verification = false;
public $avatar;
public function uploadAvatar(AvatarStorageService $avatarStorage): void
{
try {
$this->validate([
'avatar' => ['required', 'image', 'mimes:jpg,jpeg,png,webp', 'max:5120', 'dimensions:max_width=6000,max_height=6000'],
]);
$avatarStorage->store(Auth::user(), $this->avatar);
$this->reset('avatar');
$this->dispatch('avatar-updated', url: route('profile.avatar', ['v' => Auth::user()->fresh()->updated_at->timestamp]));
$this->dispatch('success', 'Profile picture updated.');
} catch (\Throwable $e) {
handleError($e, $this);
}
}
public function removeAvatar(AvatarStorageService $avatarStorage): void
{
try {
$avatarStorage->delete(Auth::user());
$this->dispatch('avatar-updated', url: null);
$this->dispatch('success', 'Profile picture removed.');
} catch (\Throwable $e) {
handleError($e, $this);
}
}
public function mount()
{
$this->userId = Auth::id();