diff --git a/app/Enums/Role.php b/app/Enums/Role.php new file mode 100644 index 00000000..0c98c00f --- /dev/null +++ b/app/Enums/Role.php @@ -0,0 +1,21 @@ + "Moderator", + self::Admin => "Administrator", + }; + } +} diff --git a/app/Filament/Resources/UserResource.php b/app/Filament/Resources/UserResource.php new file mode 100644 index 00000000..367ddded --- /dev/null +++ b/app/Filament/Resources/UserResource.php @@ -0,0 +1,120 @@ +user(); + + return $form + ->schema([ + Split::make([ + Section::make([ + Forms\Components\TextInput::make("name") + ->label("Imię i nazwisko") + ->required() + ->maxLength(255), + Forms\Components\TextInput::make("email") + ->label("E-mail") + ->required() + ->maxLength(255) + ->email() + ->unique(ignoreRecord: true), + Forms\Components\Select::make("role") + ->label("Rola") + ->disabled(fn(string $context): bool => !($context === "create") && $authUser->id === $form->model->id) + ->options(Role::class) + ->required(), + ]), + Section::make([ + Forms\Components\TextInput::make("password") + ->label("Hasło") + ->minValue(8) + ->required(fn(string $context): bool => $context === "create") + ->dehydrateStateUsing(fn(string $state): string => Hash::make($state)) + ->dehydrated(fn(?string $state): bool => filled($state)) + ->password() + ->confirmed(), + Forms\Components\TextInput::make("password_confirmation") + ->label("Potwierdź hasło") + ->required(fn(string $context): bool => $context === "create") + ->dehydrateStateUsing(fn(string $state): string => Hash::make($state)) + ->dehydrated(fn(?string $state): bool => filled($state)) + ->password(), + Forms\Components\Checkbox::make("active") + ->disabled(fn(User $user): bool => $user->id === $authUser->id) + ->label("Aktywny") + ->default(true), + ]), + ])->from("lg"), + ])->columns(1); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make("name") + ->label("Imię i nazwisko") + ->searchable(), + Tables\Columns\TextColumn::make("email") + ->label("E-mail") + ->searchable(), + Tables\Columns\CheckboxColumn::make("active") + ->disabled(fn(User $user): bool => $user->id === auth()->user()->id) + ->label("Aktywny"), + Tables\Columns\TextColumn::make("role") + ->label("Rola"), + ]) + ->filters([]) + ->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]); + } + + public static function getPages(): array + { + return [ + "index" => Pages\ListUsers::route("/"), + "create" => Pages\CreateUser::route("/create"), + "edit" => Pages\EditUser::route("/{record}/edit"), + ]; + } + + public static function canAccess(): bool + { + return auth()->user()->isAdmin(); + } + + public static function canDelete(Model $record): bool + { + /** @var User $user */ + $user = auth()->user(); + + return $user->isAdmin() && $record->id !== $user->id; + } +} diff --git a/app/Filament/Resources/UserResource/Pages/CreateUser.php b/app/Filament/Resources/UserResource/Pages/CreateUser.php new file mode 100644 index 00000000..c3e17d83 --- /dev/null +++ b/app/Filament/Resources/UserResource/Pages/CreateUser.php @@ -0,0 +1,13 @@ + "boolean", + "email_verified_at" => "datetime", + "password" => "hashed", + "role" => Role::class, + ]; public function canAccessPanel(Panel $panel): bool { - return str_ends_with($this->email, config("app.allowed_email_domain")); + return $this->active && str_ends_with($this->email, config("app.allowed_email_domain")); + } + + public function isModerator(): bool + { + return $this->role === Role::Moderator; + } + + public function isAdmin(): bool + { + return $this->role === Role::Admin; } protected function casts(): array diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index 7aa69a88..61efc64a 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -5,6 +5,7 @@ namespace Blumilksoftware\Lmt\Providers\Filament; use Blumilksoftware\Lmt\Filament\Resources\MeetupResource; +use Blumilksoftware\Lmt\Filament\Resources\UserResource; use Filament\Http\Middleware\Authenticate; use Filament\Http\Middleware\AuthenticateSession; use Filament\Http\Middleware\DisableBladeIconComponents; @@ -35,6 +36,7 @@ public function panel(Panel $panel): Panel ]) ->resources([ MeetupResource::class, + UserResource::class, ]) ->pages([]) ->widgets([]) diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 6b9d8b49..9daefc5b 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -4,6 +4,7 @@ namespace Database\Factories; +use Blumilksoftware\Lmt\Enums\Role; use Blumilksoftware\Lmt\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Facades\Hash; @@ -21,6 +22,8 @@ public function definition(): array "email" => fake()->unique()->safeEmail(), "password" => Hash::make("password"), "remember_token" => Str::random(10), + "active" => true, + "role" => Role::Admin, ]; } } diff --git a/database/migrations/2025_10_06_100523_add_role_to_users_table.php b/database/migrations/2025_10_06_100523_add_role_to_users_table.php new file mode 100644 index 00000000..82dc3c18 --- /dev/null +++ b/database/migrations/2025_10_06_100523_add_role_to_users_table.php @@ -0,0 +1,25 @@ +string("role")->default("admin"); + $table->boolean("active")->default(true); + }); + } + + public function down(): void + { + Schema::table("users", function (Blueprint $table): void { + $table->dropColumn("role"); + $table->dropColumn("active"); + }); + } +};