From a6d3b533caed79fe4fc88b602f94afd19fd4908f Mon Sep 17 00:00:00 2001 From: Javier Feliz Date: Sat, 2 Aug 2025 15:48:03 -0400 Subject: [PATCH] Move user management to its own page --- app/Livewire/ManageUsers.php | 12 ++-- .../components/layouts/app/header.blade.php | 12 ++++ .../components/layouts/app/sidebar.blade.php | 3 + resources/views/dashboard.blade.php | 6 -- .../views/livewire/manage-users.blade.php | 4 +- routes/web.php | 5 ++ tests/Feature/UserManagementPageTest.php | 59 +++++++++++++++++++ 7 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 tests/Feature/UserManagementPageTest.php diff --git a/app/Livewire/ManageUsers.php b/app/Livewire/ManageUsers.php index e51e372..5b553cc 100644 --- a/app/Livewire/ManageUsers.php +++ b/app/Livewire/ManageUsers.php @@ -8,8 +8,10 @@ use App\Models\User; use Flux\Flux; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Facades\Mail; +use Livewire\Attributes\Layout; use Livewire\Component; +#[Layout('components.layouts.app')] class ManageUsers extends Component { public string $invite_email = ''; @@ -19,11 +21,9 @@ class ManageUsers extends Component public function mount() { - // Only load data if user is authorized to view it - if (auth()->user()->can('viewAny', User::class)) { - $this->users = User::all(); - $this->invitations = Invitation::orderBy('accepted_at', 'desc')->get(); - } + // Load data since route is already protected by middleware + $this->users = User::all(); + $this->invitations = Invitation::orderBy('accepted_at', 'desc')->get(); } public function inviteUser() @@ -106,6 +106,6 @@ class ManageUsers extends Component public function render() { - return view('livewire.manage-users'); + return view('livewire.manage-users')->title('User Management'); } } diff --git a/resources/views/components/layouts/app/header.blade.php b/resources/views/components/layouts/app/header.blade.php index 015d0d0..7904c17 100644 --- a/resources/views/components/layouts/app/header.blade.php +++ b/resources/views/components/layouts/app/header.blade.php @@ -19,6 +19,12 @@ wire:navigate> {{ __('Apps') }} + @can('viewAny', App\Models\User::class) + + {{ __('User Management') }} + + @endcan @@ -90,6 +96,12 @@ :current="request()->routeIs('dashboard')" wire:navigate> {{ __('Dashboard') }} + @can('viewAny', App\Models\User::class) + + {{ __('User Management') }} + + @endcan diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index 8dd5882..aa24e73 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -14,6 +14,9 @@ {{ __('Dashboard') }} + @can('viewAny', App\Models\User::class) + {{ __('User Management') }} + @endcan diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index 002ebb9..1612bb3 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -1,11 +1,5 @@
- @can('viewAny', App\Models\User::class) -
- -
- @endcan -
diff --git a/resources/views/livewire/manage-users.blade.php b/resources/views/livewire/manage-users.blade.php index 6284d79..799869b 100644 --- a/resources/views/livewire/manage-users.blade.php +++ b/resources/views/livewire/manage-users.blade.php @@ -1,4 +1,4 @@ -@can('viewAny', App\Models\User::class) +
Users @@ -95,4 +95,4 @@ @endcan
-@endcan \ No newline at end of file +
\ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 831b1ee..8531fca 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ use App\Http\Controllers\OIDCController; use App\Livewire\ConsentScreen; +use App\Livewire\ManageUsers; use App\Livewire\Settings\Appearance; use App\Livewire\Settings\Password; use App\Livewire\Settings\Profile; @@ -19,6 +20,10 @@ Route::view('dashboard', 'dashboard') ->middleware(['auth', 'verified']) ->name('dashboard'); +Route::get('admin/users', ManageUsers::class) + ->middleware(['auth', 'can:viewAny,App\Models\User']) + ->name('admin.users'); + Route::middleware(['auth'])->group(function () { Route::redirect('settings', 'settings/profile'); diff --git a/tests/Feature/UserManagementPageTest.php b/tests/Feature/UserManagementPageTest.php new file mode 100644 index 0000000..ed9bd33 --- /dev/null +++ b/tests/Feature/UserManagementPageTest.php @@ -0,0 +1,59 @@ +admin = User::factory()->create(['is_admin' => true]); + $this->user = User::factory()->create(['is_admin' => false]); +}); + +describe('User Management Page', function () { + + it('allows admin users to access the user management page', function () { + $this->actingAs($this->admin); + + $response = $this->get(route('admin.users')); + + $response->assertStatus(200); + $response->assertSee('User Management'); + $response->assertSee('Users'); + $response->assertSee('Invitations'); + }); + + it('prevents non-admin users from accessing the user management page', function () { + $this->actingAs($this->user); + + $response = $this->get(route('admin.users')); + + $response->assertStatus(403); + }); + + it('redirects unauthenticated users to login', function () { + $response = $this->get(route('admin.users')); + + $response->assertRedirect(route('login')); + }); + + it('shows the user management navigation link only to admins', function () { + // Test admin sees the link + $this->actingAs($this->admin); + $response = $this->get(route('dashboard')); + $response->assertSee('User Management'); + + // Test regular user doesn't see the link in navigation + $this->actingAs($this->user); + $response = $this->get(route('dashboard')); + $response->assertDontSee('href="' . route('admin.users') . '"', false); + }); + + it('properly displays the page title', function () { + $this->actingAs($this->admin); + + $response = $this->get(route('admin.users')); + + $response->assertSee('User Management', false); + }); +}); \ No newline at end of file