diff --git a/app/Extensions/Avatar/AvatarProvider.php b/app/Extensions/Avatar/AvatarProvider.php index 2c707e696..978c95eba 100644 --- a/app/Extensions/Avatar/AvatarProvider.php +++ b/app/Extensions/Avatar/AvatarProvider.php @@ -2,11 +2,11 @@ namespace App\Extensions\Avatar; -use Filament\AvatarProviders\Contracts\AvatarProvider as AvatarProviderContract; +use App\Models\User; use Illuminate\Support\Arr; use Illuminate\Support\Str; -abstract class AvatarProvider implements AvatarProviderContract +abstract class AvatarProvider { /** * @var array @@ -33,6 +33,8 @@ abstract class AvatarProvider implements AvatarProviderContract abstract public function getId(): string; + abstract public function get(User $user): ?string; + public function getName(): string { return Str::title($this->getId()); diff --git a/app/Extensions/Avatar/Providers/GravatarProvider.php b/app/Extensions/Avatar/Providers/GravatarProvider.php index 6f47a119a..21e69c587 100644 --- a/app/Extensions/Avatar/Providers/GravatarProvider.php +++ b/app/Extensions/Avatar/Providers/GravatarProvider.php @@ -4,8 +4,6 @@ namespace App\Extensions\Avatar\Providers; use App\Extensions\Avatar\AvatarProvider; use App\Models\User; -use Illuminate\Contracts\Auth\Authenticatable; -use Illuminate\Database\Eloquent\Model; class GravatarProvider extends AvatarProvider { @@ -14,10 +12,9 @@ class GravatarProvider extends AvatarProvider return 'gravatar'; } - public function get(Model|Authenticatable $record): string + public function get(User $user): string { - /** @var User $record */ - return 'https://gravatar.com/avatar/' . md5($record->email); + return 'https://gravatar.com/avatar/' . md5($user->email); } public static function register(): self diff --git a/app/Extensions/Avatar/Providers/LocalAvatarProvider.php b/app/Extensions/Avatar/Providers/LocalAvatarProvider.php deleted file mode 100644 index f84cc5c4c..000000000 --- a/app/Extensions/Avatar/Providers/LocalAvatarProvider.php +++ /dev/null @@ -1,29 +0,0 @@ -getKey() . '.png'; - - return Storage::disk('public')->exists($path) ? Storage::url($path) : (new FilamentUiAvatarsProvider())->get($record); - } - - public static function register(): self - { - return new self(); - } -} diff --git a/app/Extensions/Avatar/Providers/UiAvatarsProvider.php b/app/Extensions/Avatar/Providers/UiAvatarsProvider.php index e1df16b16..4ee211cdb 100644 --- a/app/Extensions/Avatar/Providers/UiAvatarsProvider.php +++ b/app/Extensions/Avatar/Providers/UiAvatarsProvider.php @@ -3,9 +3,7 @@ namespace App\Extensions\Avatar\Providers; use App\Extensions\Avatar\AvatarProvider; -use Filament\AvatarProviders\UiAvatarsProvider as FilamentUiAvatarsProvider; -use Illuminate\Contracts\Auth\Authenticatable; -use Illuminate\Database\Eloquent\Model; +use App\Models\User; class UiAvatarsProvider extends AvatarProvider { @@ -19,9 +17,10 @@ class UiAvatarsProvider extends AvatarProvider return 'UI Avatars'; } - public function get(Model|Authenticatable $record): string + public function get(User $user): ?string { - return (new FilamentUiAvatarsProvider())->get($record); + // UI Avatars is the default of filament so just return null here + return null; } public static function register(): self diff --git a/app/Filament/Admin/Pages/Settings.php b/app/Filament/Admin/Pages/Settings.php index 026e6a391..78803125c 100644 --- a/app/Filament/Admin/Pages/Settings.php +++ b/app/Filament/Admin/Pages/Settings.php @@ -161,11 +161,20 @@ class Settings extends Page implements HasForms ->default(env('FILAMENT_TOP_NAVIGATION', config('panel.filament.top-navigation'))), Select::make('FILAMENT_AVATAR_PROVIDER') ->label(trans('admin/setting.general.avatar_provider')) - ->columnSpan(2) ->native(false) ->options(collect(AvatarProvider::getAll())->mapWithKeys(fn ($provider) => [$provider->getId() => $provider->getName()])) ->selectablePlaceholder(false) ->default(env('FILAMENT_AVATAR_PROVIDER', config('panel.filament.avatar-provider'))), + Toggle::make('FILAMENT_UPLOADABLE_AVATARS') + ->label(trans('admin/setting.general.uploadable_avatars')) + ->inline(false) + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->formatStateUsing(fn ($state) => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('FILAMENT_UPLOADABLE_AVATARS', (bool) $state)) + ->default(env('FILAMENT_UPLOADABLE_AVATARS', config('panel.filament.uploadable-avatars'))), ]), ToggleButtons::make('PANEL_USE_BINARY_PREFIX') ->label(trans('admin/setting.general.unit_prefix')) diff --git a/app/Filament/Pages/Auth/EditProfile.php b/app/Filament/Pages/Auth/EditProfile.php index 5ad30f707..4b167bf53 100644 --- a/app/Filament/Pages/Auth/EditProfile.php +++ b/app/Filament/Pages/Auth/EditProfile.php @@ -128,7 +128,7 @@ class EditProfile extends BaseEditProfile ->options(fn (LanguageService $languageService) => $languageService->getAvailableLanguages()) ->native(false), FileUpload::make('avatar') - ->visible(fn () => config('panel.filament.avatar-provider') === 'local') + ->visible(fn () => config('panel.filament.uploadable-avatars')) ->avatar() ->acceptedFileTypes(['image/png']) ->directory('avatars') diff --git a/app/Models/User.php b/app/Models/User.php index 8698bd2eb..10e56427f 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Contracts\Validatable; use App\Exceptions\DisplayException; +use App\Extensions\Avatar\AvatarProvider; use App\Rules\Username; use App\Facades\Activity; use App\Traits\HasValidation; @@ -23,6 +24,7 @@ use Illuminate\Auth\Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Builder; use App\Models\Traits\HasAccessTokens; +use Filament\Models\Contracts\HasAvatar; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Auth\Access\Authorizable; @@ -30,6 +32,7 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; +use Illuminate\Support\Facades\Storage; use ResourceBundle; use Spatie\Permission\Traits\HasRoles; @@ -87,7 +90,7 @@ use Spatie\Permission\Traits\HasRoles; * @method static Builder|User whereUsername($value) * @method static Builder|User whereUuid($value) */ -class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, FilamentUser, HasName, HasTenants, Validatable +class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, FilamentUser, HasAvatar, HasName, HasTenants, Validatable { use Authenticatable; use Authorizable { can as protected canned; } @@ -372,6 +375,21 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac return $this->username; } + public function getFilamentAvatarUrl(): ?string + { + if (config('panel.filament.uploadable-avatars')) { + $path = "avatars/$this->id.png"; + + if (Storage::disk('public')->exists($path)) { + return Storage::url($path); + } + } + + $provider = AvatarProvider::getProvider(config('panel.filament.avatar-provider')); + + return $provider?->get($this); + } + public function canTarget(Model $user): bool { if ($this->isRootAdmin()) { diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index fccfa461e..2dd341b8d 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -11,7 +11,6 @@ use App\Checks\PanelVersionCheck; use App\Checks\ScheduleCheck; use App\Checks\UsedDiskSpaceCheck; use App\Extensions\Avatar\Providers\GravatarProvider; -use App\Extensions\Avatar\Providers\LocalAvatarProvider; use App\Extensions\Avatar\Providers\UiAvatarsProvider; use App\Extensions\OAuth\Providers\GitlabProvider; use App\Models; @@ -121,7 +120,6 @@ class AppServiceProvider extends ServiceProvider // Default Avatar providers GravatarProvider::register(); UiAvatarsProvider::register(); - LocalAvatarProvider::register(); FilamentColor::register([ 'danger' => Color::Red, diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index afee87b13..35c03f0d5 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -2,7 +2,6 @@ namespace App\Providers\Filament; -use App\Extensions\Avatar\AvatarProvider; use App\Filament\Pages\Auth\Login; use App\Filament\Pages\Auth\EditProfile; use App\Http\Middleware\LanguageMiddleware; @@ -39,7 +38,6 @@ class AdminPanelProvider extends PanelProvider ->favicon(config('app.favicon', '/pelican.ico')) ->topNavigation(config('panel.filament.top-navigation', false)) ->maxContentWidth(config('panel.filament.display-width', 'screen-2xl')) - ->defaultAvatarProvider(fn () => get_class(AvatarProvider::getProvider(config('panel.filament.avatar-provider')))) ->login(Login::class) ->passwordReset() ->userMenuItems([ diff --git a/app/Providers/Filament/AppPanelProvider.php b/app/Providers/Filament/AppPanelProvider.php index da903f9c2..44446d157 100644 --- a/app/Providers/Filament/AppPanelProvider.php +++ b/app/Providers/Filament/AppPanelProvider.php @@ -2,7 +2,6 @@ namespace App\Providers\Filament; -use App\Extensions\Avatar\AvatarProvider; use App\Filament\Pages\Auth\Login; use App\Filament\Pages\Auth\EditProfile; use Filament\Facades\Filament; @@ -35,7 +34,6 @@ class AppPanelProvider extends PanelProvider ->favicon(config('app.favicon', '/pelican.ico')) ->topNavigation(config('panel.filament.top-navigation', false)) ->maxContentWidth(config('panel.filament.display-width', 'screen-2xl')) - ->defaultAvatarProvider(fn () => get_class(AvatarProvider::getProvider(config('panel.filament.avatar-provider')))) ->navigation(false) ->profile(EditProfile::class, false) ->login(Login::class) diff --git a/app/Providers/Filament/ServerPanelProvider.php b/app/Providers/Filament/ServerPanelProvider.php index 0fbb41d4e..6a4051da5 100644 --- a/app/Providers/Filament/ServerPanelProvider.php +++ b/app/Providers/Filament/ServerPanelProvider.php @@ -2,7 +2,6 @@ namespace App\Providers\Filament; -use App\Extensions\Avatar\AvatarProvider; use App\Filament\App\Resources\ServerResource\Pages\ListServers; use App\Filament\Pages\Auth\Login; use App\Filament\Admin\Resources\ServerResource\Pages\EditServer; @@ -42,7 +41,6 @@ class ServerPanelProvider extends PanelProvider ->favicon(config('app.favicon', '/pelican.ico')) ->topNavigation(config('panel.filament.top-navigation', false)) ->maxContentWidth(config('panel.filament.display-width', 'screen-2xl')) - ->defaultAvatarProvider(fn () => get_class(AvatarProvider::getProvider(config('panel.filament.avatar-provider')))) ->login(Login::class) ->passwordReset() ->userMenuItems([ diff --git a/config/panel.php b/config/panel.php index 062ace41f..504092db4 100644 --- a/config/panel.php +++ b/config/panel.php @@ -53,6 +53,7 @@ return [ 'top-navigation' => env('FILAMENT_TOP_NAVIGATION', false), 'display-width' => env('FILAMENT_WIDTH', 'screen-2xl'), 'avatar-provider' => env('FILAMENT_AVATAR_PROVIDER', 'gravatar'), + 'uploadable-avatars' => env('FILAMENT_UPLOADABLE_AVATARS', false), ], 'use_binary_prefix' => env('PANEL_USE_BINARY_PREFIX', true), diff --git a/lang/en/admin/setting.php b/lang/en/admin/setting.php index a9ed2cf91..969dab597 100644 --- a/lang/en/admin/setting.php +++ b/lang/en/admin/setting.php @@ -35,6 +35,7 @@ return [ 'set_to_cf' => 'Set to Cloudflare IPs', 'display_width' => 'Display Width', 'avatar_provider' => 'Avatar Provider', + 'uploadable_avatars' => 'Allow users to upload own avatar?', ], 'captcha' => [ 'enable' => 'Enable',