mirror of
https://github.com/pelican-dev/panel.git
synced 2025-11-09 12:39:30 +01:00
add toggle for externally managed users
This commit is contained in:
parent
8e006ac32d
commit
a9165c66f7
@ -33,6 +33,7 @@ use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Components\Repeater;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Toggle;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\PageRegistration;
|
||||
@ -224,67 +225,73 @@ class UserResource extends Resource
|
||||
'md' => 1,
|
||||
'lg' => 1,
|
||||
]),
|
||||
Select::make('timezone')
|
||||
->label(trans('profile.timezone'))
|
||||
Toggle::make('is_managed_externally')
|
||||
->label(trans('admin/user.is_managed_externally'))
|
||||
->hintIcon('tabler-question-mark', trans('admin/user.is_managed_externally_helper'))
|
||||
->inline(false)
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'md' => 1,
|
||||
'lg' => 1,
|
||||
])
|
||||
->required()
|
||||
->prefixIcon('tabler-clock-pin')
|
||||
->default(fn () => config('app.timezone', 'UTC'))
|
||||
->selectablePlaceholder(false)
|
||||
->options(fn () => collect(DateTimeZone::listIdentifiers())->mapWithKeys(fn ($tz) => [$tz => $tz]))
|
||||
->searchable()
|
||||
->native(false),
|
||||
Select::make('language')
|
||||
->label(trans('profile.language'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'md' => 1,
|
||||
'lg' => 1,
|
||||
])
|
||||
->required()
|
||||
->prefixIcon('tabler-flag')
|
||||
->live()
|
||||
->default('en')
|
||||
->searchable()
|
||||
->selectablePlaceholder(false)
|
||||
->options(fn (LanguageService $languageService) => $languageService->getAvailableLanguages())
|
||||
->native(false),
|
||||
FileUpload::make('avatar')
|
||||
->visible(fn (?User $user, FileUpload $fileUpload) => $user ? $fileUpload->getDisk()->exists($fileUpload->getDirectory() . '/' . $user->id . '.png') : false)
|
||||
->avatar()
|
||||
->directory('avatars')
|
||||
->disk('public')
|
||||
->formatStateUsing(function (FileUpload $fileUpload, ?User $user) {
|
||||
if (!$user) {
|
||||
return null;
|
||||
}
|
||||
$path = $fileUpload->getDirectory() . '/' . $user->id . '.png';
|
||||
if ($fileUpload->getDisk()->exists($path)) {
|
||||
return $path;
|
||||
}
|
||||
})
|
||||
->deleteUploadedFileUsing(function (FileUpload $fileUpload, $file) {
|
||||
if ($file instanceof TemporaryUploadedFile) {
|
||||
return $file->delete();
|
||||
}
|
||||
]),
|
||||
Section::make(trans('profile.tabs.customization'))
|
||||
->collapsible()
|
||||
->columnSpanFull()
|
||||
->columns(2)
|
||||
->schema([
|
||||
Select::make('timezone')
|
||||
->label(trans('profile.timezone'))
|
||||
->required()
|
||||
->prefixIcon('tabler-clock-pin')
|
||||
->default(fn () => config('app.timezone', 'UTC'))
|
||||
->selectablePlaceholder(false)
|
||||
->options(fn () => collect(DateTimeZone::listIdentifiers())->mapWithKeys(fn ($tz) => [$tz => $tz]))
|
||||
->searchable()
|
||||
->native(false),
|
||||
Select::make('language')
|
||||
->label(trans('profile.language'))
|
||||
->required()
|
||||
->prefixIcon('tabler-flag')
|
||||
->live()
|
||||
->default('en')
|
||||
->searchable()
|
||||
->selectablePlaceholder(false)
|
||||
->options(fn (LanguageService $languageService) => $languageService->getAvailableLanguages())
|
||||
->native(false),
|
||||
FileUpload::make('avatar')
|
||||
->visible(fn (?User $user, FileUpload $fileUpload) => $user ? $fileUpload->getDisk()->exists($fileUpload->getDirectory() . '/' . $user->id . '.png') : false)
|
||||
->columnSpanFull()
|
||||
->avatar()
|
||||
->directory('avatars')
|
||||
->disk('public')
|
||||
->formatStateUsing(function (FileUpload $fileUpload, ?User $user) {
|
||||
if (!$user) {
|
||||
return null;
|
||||
}
|
||||
$path = $fileUpload->getDirectory() . '/' . $user->id . '.png';
|
||||
if ($fileUpload->getDisk()->exists($path)) {
|
||||
return $path;
|
||||
}
|
||||
})
|
||||
->deleteUploadedFileUsing(function (FileUpload $fileUpload, $file) {
|
||||
if ($file instanceof TemporaryUploadedFile) {
|
||||
return $file->delete();
|
||||
}
|
||||
|
||||
if ($fileUpload->getDisk()->exists($file)) {
|
||||
return $fileUpload->getDisk()->delete($file);
|
||||
}
|
||||
}),
|
||||
if ($fileUpload->getDisk()->exists($file)) {
|
||||
return $fileUpload->getDisk()->delete($file);
|
||||
}
|
||||
}),
|
||||
]),
|
||||
Section::make(trans('profile.tabs.oauth'))
|
||||
->visible(fn (?User $user) => $user)
|
||||
->collapsible()
|
||||
->columnSpanFull()
|
||||
->schema(function (OAuthService $oauthService, ?User $user) {
|
||||
|
||||
if (!$user) {
|
||||
return;
|
||||
}
|
||||
|
||||
$actions = [];
|
||||
foreach ($user->oauth ?? [] as $schema => $_) {
|
||||
$schema = $oauthService->get($schema);
|
||||
|
||||
@ -94,12 +94,14 @@ class EditProfile extends BaseEditProfile
|
||||
->icon('tabler-user-cog')
|
||||
->schema([
|
||||
TextInput::make('username')
|
||||
->disabled(fn (User $user) => $user->is_managed_externally)
|
||||
->prefixIcon('tabler-user')
|
||||
->label(trans('profile.username'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->unique(),
|
||||
TextInput::make('email')
|
||||
->disabled(fn (User $user) => $user->is_managed_externally)
|
||||
->prefixIcon('tabler-mail')
|
||||
->label(trans('profile.email'))
|
||||
->email()
|
||||
@ -107,6 +109,7 @@ class EditProfile extends BaseEditProfile
|
||||
->maxLength(255)
|
||||
->unique(),
|
||||
TextInput::make('password')
|
||||
->hidden(fn (User $user) => $user->is_managed_externally)
|
||||
->label(trans('profile.password'))
|
||||
->password()
|
||||
->prefixIcon('tabler-password')
|
||||
@ -537,7 +540,6 @@ class EditProfile extends BaseEditProfile
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
|
||||
])
|
||||
->operation('edit')
|
||||
->model($this->getUser())
|
||||
|
||||
@ -22,6 +22,7 @@ class StoreUserRequest extends ApplicationApiRequest
|
||||
|
||||
return collect($rules)->only([
|
||||
'external_id',
|
||||
'is_managed_externally',
|
||||
'email',
|
||||
'username',
|
||||
'password',
|
||||
@ -39,6 +40,7 @@ class StoreUserRequest extends ApplicationApiRequest
|
||||
{
|
||||
return [
|
||||
'external_id' => 'Third Party Identifier',
|
||||
'is_managed_externally' => 'Is managed by Third Party?',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ class UpdateEmailRequest extends ClientApiRequest
|
||||
throw new InvalidPasswordProvidedException(trans('validation.internal.invalid_password'));
|
||||
}
|
||||
|
||||
return true;
|
||||
return !$this->user()->is_managed_externally;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
|
||||
@ -25,7 +25,7 @@ class UpdatePasswordRequest extends ClientApiRequest
|
||||
throw new InvalidPasswordProvidedException(trans('validation.internal.invalid_password'));
|
||||
}
|
||||
|
||||
return true;
|
||||
return !$this->user()->is_managed_externally;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
|
||||
@ -48,6 +48,7 @@ use Spatie\Permission\Traits\HasRoles;
|
||||
*
|
||||
* @property int $id
|
||||
* @property string|null $external_id
|
||||
* @property bool $is_managed_externally
|
||||
* @property string $uuid
|
||||
* @property string $username
|
||||
* @property string $email
|
||||
@ -117,6 +118,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
||||
*/
|
||||
protected $fillable = [
|
||||
'external_id',
|
||||
'is_managed_externally',
|
||||
'username',
|
||||
'email',
|
||||
'password',
|
||||
@ -139,6 +141,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
||||
*/
|
||||
protected $attributes = [
|
||||
'external_id' => null,
|
||||
'is_managed_externally' => false,
|
||||
'language' => 'en',
|
||||
'timezone' => 'UTC',
|
||||
'mfa_app_secret' => null,
|
||||
@ -153,6 +156,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
||||
'uuid' => ['nullable', 'string', 'size:36', 'unique:users,uuid'],
|
||||
'email' => ['required', 'email', 'between:1,255', 'unique:users,email'],
|
||||
'external_id' => ['sometimes', 'nullable', 'string', 'max:255', 'unique:users,external_id'],
|
||||
'is_managed_externally' => ['boolean'],
|
||||
'username' => ['required', 'between:1,255', 'unique:users,username'],
|
||||
'password' => ['sometimes', 'nullable', 'string'],
|
||||
'language' => ['string'],
|
||||
|
||||
@ -31,6 +31,7 @@ class UserTransformer extends BaseTransformer
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'external_id' => $user->external_id,
|
||||
'is_managed_externally' => $user->is_managed_externally,
|
||||
'uuid' => $user->uuid,
|
||||
'username' => $user->username,
|
||||
'email' => $user->email,
|
||||
|
||||
@ -26,6 +26,7 @@ class UserFactory extends Factory
|
||||
|
||||
return [
|
||||
'external_id' => null,
|
||||
'is_managed_externally' => false,
|
||||
'uuid' => Uuid::uuid4()->toString(),
|
||||
'username' => $this->faker->userName() . '_' . Str::random(10),
|
||||
'email' => Str::random(32) . '@example.com',
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->boolean('is_managed_externally')->default(false)->after('external_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('is_managed_externally');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -10,6 +10,8 @@ return [
|
||||
'username' => 'Username',
|
||||
'password' => 'Password',
|
||||
'external_id' => 'External ID',
|
||||
'is_managed_externally' => 'Is managed externally?',
|
||||
'is_managed_externally_helper' => 'If your users are managed by external software (e.g. a billing software) you may enable this to prevent users from changing their username, e-mail and password from within the panel.',
|
||||
'password_help' => 'Providing a user password is optional. New user email will prompt users to create a password the first time they login.',
|
||||
'admin_roles' => 'Admin Roles',
|
||||
'roles' => 'Roles',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user