This commit is contained in:
Vehikl 2025-05-22 17:07:49 -04:00
parent 1dc1b13e8e
commit d9257fdb4f
9 changed files with 87 additions and 60 deletions

View File

@ -3,40 +3,45 @@
namespace App\Extensions\Avatar; namespace App\Extensions\Avatar;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Arr; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
abstract class AvatarProvider class AvatarProvider
{ {
/** /** @var AvatarSchemaInterface[] */
* @var array<string, static> private array $providers = [];
*/
protected static array $providers = [];
public static function getProvider(string $id): ?self
{
return Arr::get(static::$providers, $id);
}
/** /**
* @return array<string, static> * @return AvatarSchemaInterface[] | AvatarSchemaInterface | null
*/ */
public static function getAll(): array public function get(?string $id = null): array|AvatarSchemaInterface|null
{ {
return static::$providers; return $id ? array_get($this->providers, $id) : $this->providers;
} }
public function __construct() public function getActiveSchema(): ?AvatarSchemaInterface
{ {
static::$providers[$this->getId()] = $this; return $this->get(config('panel.filament.avatar-provider'));
} }
abstract public function getId(): string; public function getAvatarUrl(User $user): ?string
abstract public function get(User $user): ?string;
public function getName(): string
{ {
return Str::title($this->getId()); if (config('panel.filament.uploadable-avatars')) {
$path = "avatars/$user->id.png";
if (Storage::disk('public')->exists($path)) {
return Storage::url($path);
}
}
return $this->getActiveSchema()?->get($user);
}
public function register(AvatarSchemaInterface $provider): void
{
if (array_key_exists($provider->getId(), $this->providers)) {
return;
}
$this->providers[$provider->getId()] = $provider;
} }
} }

View File

@ -0,0 +1,14 @@
<?php
namespace App\Extensions\Avatar;
use App\Models\User;
interface AvatarSchemaInterface
{
public function getId(): string;
public function getName(): string;
public function get(User $user): ?string;
}

View File

@ -1,24 +1,24 @@
<?php <?php
namespace App\Extensions\Avatar\Providers; namespace App\Extensions\Avatar\Schemas;
use App\Extensions\Avatar\AvatarProvider; use App\Extensions\Avatar\AvatarSchemaInterface;
use App\Models\User; use App\Models\User;
class GravatarProvider extends AvatarProvider class GravatarSchema implements AvatarSchemaInterface
{ {
public function getId(): string public function getId(): string
{ {
return 'gravatar'; return 'gravatar';
} }
public function getName(): string
{
return 'Gravatar';
}
public function get(User $user): string public function get(User $user): string
{ {
return 'https://gravatar.com/avatar/' . md5($user->email); return 'https://gravatar.com/avatar/' . md5($user->email);
} }
public static function register(): self
{
return new self();
}
} }

View File

@ -1,11 +1,11 @@
<?php <?php
namespace App\Extensions\Avatar\Providers; namespace App\Extensions\Avatar\Schemas;
use App\Extensions\Avatar\AvatarProvider; use App\Extensions\Avatar\AvatarSchemaInterface;
use App\Models\User; use App\Models\User;
class UiAvatarsProvider extends AvatarProvider class UiAvatarsSchema implements AvatarSchemaInterface
{ {
public function getId(): string public function getId(): string
{ {
@ -22,9 +22,4 @@ class UiAvatarsProvider extends AvatarProvider
// UI Avatars is the default of filament so just return null here // UI Avatars is the default of filament so just return null here
return null; return null;
} }
public static function register(): self
{
return new self();
}
} }

View File

@ -54,6 +54,8 @@ class Settings extends Page implements HasForms
protected OAuthProvider $oauthProvider; protected OAuthProvider $oauthProvider;
protected AvatarProvider $avatarProvider;
/** @var array<mixed>|null */ /** @var array<mixed>|null */
public ?array $data = []; public ?array $data = [];
@ -62,9 +64,10 @@ class Settings extends Page implements HasForms
$this->form->fill(); $this->form->fill();
} }
public function boot(OAuthProvider $oauthProvider): void public function boot(OAuthProvider $oauthProvider, AvatarProvider $avatarProvider): void
{ {
$this->oauthProvider = $oauthProvider; $this->oauthProvider = $oauthProvider;
$this->avatarProvider = $avatarProvider;
} }
public static function canAccess(): bool public static function canAccess(): bool
@ -174,7 +177,7 @@ class Settings extends Page implements HasForms
Select::make('FILAMENT_AVATAR_PROVIDER') Select::make('FILAMENT_AVATAR_PROVIDER')
->label(trans('admin/setting.general.avatar_provider')) ->label(trans('admin/setting.general.avatar_provider'))
->native(false) ->native(false)
->options(collect(AvatarProvider::getAll())->mapWithKeys(fn ($provider) => [$provider->getId() => $provider->getName()])) ->options(collect($this->avatarProvider->get())->mapWithKeys(fn ($provider) => [$provider->getId() => $provider->getName()]))
->selectablePlaceholder(false) ->selectablePlaceholder(false)
->default(env('FILAMENT_AVATAR_PROVIDER', config('panel.filament.avatar-provider'))), ->default(env('FILAMENT_AVATAR_PROVIDER', config('panel.filament.avatar-provider'))),
Toggle::make('FILAMENT_UPLOADABLE_AVATARS') Toggle::make('FILAMENT_UPLOADABLE_AVATARS')

View File

@ -6,7 +6,6 @@ use App\Contracts\Validatable;
use App\Exceptions\DisplayException; use App\Exceptions\DisplayException;
use App\Extensions\Avatar\AvatarProvider; use App\Extensions\Avatar\AvatarProvider;
use App\Rules\Username; use App\Rules\Username;
use App\Facades\Activity;
use App\Traits\HasValidation; use App\Traits\HasValidation;
use DateTimeZone; use DateTimeZone;
use Filament\Models\Contracts\FilamentUser; use Filament\Models\Contracts\FilamentUser;
@ -18,6 +17,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Validation\Rules\In; use Illuminate\Validation\Rules\In;
use Illuminate\Auth\Authenticatable; use Illuminate\Auth\Authenticatable;
@ -32,7 +32,6 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract; use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Support\Facades\Storage;
use ResourceBundle; use ResourceBundle;
use Spatie\Permission\Traits\HasRoles; use Spatie\Permission\Traits\HasRoles;
@ -393,17 +392,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
public function getFilamentAvatarUrl(): ?string public function getFilamentAvatarUrl(): ?string
{ {
if (config('panel.filament.uploadable-avatars')) { return App::call(function (AvatarProvider $provider) {
$path = "avatars/$this->id.png"; return $provider->getAvatarUrl($this);
});
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 $model): bool public function canTarget(Model $model): bool

View File

@ -10,8 +10,6 @@ use App\Checks\NodeVersionsCheck;
use App\Checks\PanelVersionCheck; use App\Checks\PanelVersionCheck;
use App\Checks\ScheduleCheck; use App\Checks\ScheduleCheck;
use App\Checks\UsedDiskSpaceCheck; use App\Checks\UsedDiskSpaceCheck;
use App\Extensions\Avatar\Providers\GravatarProvider;
use App\Extensions\Avatar\Providers\UiAvatarsProvider;
use App\Extensions\Captcha\Providers\TurnstileProvider; use App\Extensions\Captcha\Providers\TurnstileProvider;
use App\Models; use App\Models;
use App\Services\Helpers\SoftwareVersionService; use App\Services\Helpers\SoftwareVersionService;
@ -97,10 +95,6 @@ class AppServiceProvider extends ServiceProvider
// Default Captcha provider // Default Captcha provider
TurnstileProvider::register($app); TurnstileProvider::register($app);
// Default Avatar providers
GravatarProvider::register();
UiAvatarsProvider::register();
FilamentColor::register([ FilamentColor::register([
'danger' => Color::Red, 'danger' => Color::Red,
'gray' => Color::Zinc, 'gray' => Color::Zinc,

View File

@ -0,0 +1,24 @@
<?php
namespace App\Providers\Extensions;
use App\Extensions\Avatar\AvatarProvider;
use App\Extensions\Avatar\Schemas\GravatarSchema;
use App\Extensions\Avatar\Schemas\UiAvatarsSchema;
use Illuminate\Support\ServiceProvider;
class AvatarServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(AvatarProvider::class, function ($app) {
$provider = new AvatarProvider();
// Default Avatar providers
$provider->register(new GravatarSchema());
$provider->register(new UiAvatarsSchema());
return $provider;
});
}
}

View File

@ -8,6 +8,7 @@ return [
App\Providers\Filament\AdminPanelProvider::class, App\Providers\Filament\AdminPanelProvider::class,
App\Providers\Filament\AppPanelProvider::class, App\Providers\Filament\AppPanelProvider::class,
App\Providers\Filament\ServerPanelProvider::class, App\Providers\Filament\ServerPanelProvider::class,
App\Providers\Extensions\AvatarServiceProvider::class,
App\Providers\Extensions\FeatureServiceProvider::class, App\Providers\Extensions\FeatureServiceProvider::class,
App\Providers\Extensions\OAuthServiceProvider::class, App\Providers\Extensions\OAuthServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,