From f9bdfeabb6f398d615e7f964333447525d156acf Mon Sep 17 00:00:00 2001 From: krzysztofkozyra021 Date: Mon, 16 Mar 2026 14:46:57 +0100 Subject: [PATCH 1/2] Admin can manage users --- app/Http/Controllers/Admin/UserController.php | 60 ++++++++++++++++ app/Http/Requests/Admin/UpdateUserRequest.php | 31 ++++++++ app/Policies/UserPolicy.php | 25 +++++++ database/seeders/DemoSeeder.php | 6 +- resources/views/admin/users/edit.blade.php | 41 +++++++++++ resources/views/admin/users/index.blade.php | 70 +++++++++++++++++++ routes/web.php | 10 ++- 7 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 app/Http/Controllers/Admin/UserController.php create mode 100644 app/Http/Requests/Admin/UpdateUserRequest.php create mode 100644 app/Policies/UserPolicy.php create mode 100644 resources/views/admin/users/edit.blade.php create mode 100644 resources/views/admin/users/index.blade.php diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php new file mode 100644 index 0000000..c2520e2 --- /dev/null +++ b/app/Http/Controllers/Admin/UserController.php @@ -0,0 +1,60 @@ +authorize("viewAny", User::class); + + $query = User::query(); + + if ($request->filled("search")) { + $search = $request->input("search"); + $query->where(function ($q) use ($search): void { + $q->where("name", "like", "%" . $search . "%") + ->orWhere("email", "like", "%" . $search . "%"); + }); + } + + $users = $query->latest()->paginate(20)->withQueryString(); + + return view("admin.users.index", compact("users")); + } + + public function edit(User $user): View + { + $this->authorize("update", $user); + + return view("admin.users.edit", compact("user")); + } + + public function update(UpdateUserRequest $request, User $user): RedirectResponse + { + $user->update($request->validated()); + + return redirect()->route("admin.users.index"); + } + + public function destroy(User $user): RedirectResponse + { + $this->authorize("delete", $user); + + $user->delete(); + + return redirect()->route("admin.users.index"); + } +} diff --git a/app/Http/Requests/Admin/UpdateUserRequest.php b/app/Http/Requests/Admin/UpdateUserRequest.php new file mode 100644 index 0000000..849bc46 --- /dev/null +++ b/app/Http/Requests/Admin/UpdateUserRequest.php @@ -0,0 +1,31 @@ +user()->can("update", $this->route("user")); + } + + public function rules(): array + { + return [ + "is_admin" => ["boolean"], + "is_team_member" => ["boolean"], + ]; + } + + protected function prepareForValidation(): void + { + $this->merge([ + "is_admin" => $this->boolean("is_admin"), + "is_team_member" => $this->boolean("is_team_member"), + ]); + } +} diff --git a/app/Policies/UserPolicy.php b/app/Policies/UserPolicy.php new file mode 100644 index 0000000..fb2995d --- /dev/null +++ b/app/Policies/UserPolicy.php @@ -0,0 +1,25 @@ +is_admin; + } + + public function update(User $user, User $model): bool + { + return $user->is_admin; + } + + public function delete(User $user, User $model): bool + { + return $user->is_admin && $user->id !== $model->id; + } +} diff --git a/database/seeders/DemoSeeder.php b/database/seeders/DemoSeeder.php index 73cfee4..92c8880 100644 --- a/database/seeders/DemoSeeder.php +++ b/database/seeders/DemoSeeder.php @@ -14,7 +14,11 @@ class DemoSeeder extends Seeder public function run(): void { Hop::factory(50)->create(); - User::factory(10)->create(); + User::factory(30)->create(); + + User::factory(["name" => "Admin", "email" => "admin@example.com", "password" => "password"])->admin()->create(); + User::factory(["name" => "Team Member", "email" => "member@example.com", "password" => "password"])->teamMember()->create(); + HopQuery::factory(10)->for(User::first())->create(); } } diff --git a/resources/views/admin/users/edit.blade.php b/resources/views/admin/users/edit.blade.php new file mode 100644 index 0000000..0d9a82d --- /dev/null +++ b/resources/views/admin/users/edit.blade.php @@ -0,0 +1,41 @@ + + +

+ {{ __('Edit User: ') }} {{ $user->name }} +

+
+ +
+
+
+
+
+ @csrf + @method('PUT') + +
+ +
+ +
+ + + +
+ +
+ {{ __('Save') }} + {{ __('Cancel') }} +
+
+
+
+
+
+
diff --git a/resources/views/admin/users/index.blade.php b/resources/views/admin/users/index.blade.php new file mode 100644 index 0000000..337f173 --- /dev/null +++ b/resources/views/admin/users/index.blade.php @@ -0,0 +1,70 @@ + + +

+ {{ __('Users') }} +

+
+ +
+
+
+
+
+
+ + Search + +
+ +
+ + + + + + + + + + + + + @foreach ($users as $user) + + + + + + + + + @endforeach + +
NameEmailAdminTeam MemberCreated AtActions
{{ $user->name }}{{ $user->email }} + + {{ $user->is_admin ? 'Yes' : 'No' }} + + + + {{ $user->is_team_member ? 'Yes' : 'No' }} + + {{ $user->created_at->format('Y-m-d H:i') }} + Edit + @if (auth()->id() !== $user->id) +
+ @csrf + @method('DELETE') + +
+ @endif +
+
+ +
+ {{ $users->links() }} +
+
+
+
+
+
diff --git a/routes/web.php b/routes/web.php index b90ab68..691bd47 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use HopsWeb\Http\Controllers\Admin\UserController; use HopsWeb\Http\Controllers\ProfileController; use Illuminate\Support\Facades\Route; @@ -9,8 +10,15 @@ Route::get("/dashboard", fn() => view("dashboard"))->middleware(["auth", "verified"])->name("dashboard"); -Route::middleware("auth")->group(function (): void { +Route::middleware(["auth"])->group(function (): void { Route::get("/profile", [ProfileController::class, "edit"])->name("profile.edit"); Route::patch("/profile", [ProfileController::class, "update"])->name("profile.update"); Route::delete("/profile", [ProfileController::class, "destroy"])->name("profile.destroy"); + + Route::prefix("admin")->name("admin.")->group(function (): void { + Route::get("/users", [UserController::class, "index"])->name("users.index"); + Route::get("/users/{user}/edit", [UserController::class, "edit"])->name("users.edit"); + Route::put("/users/{user}", [UserController::class, "update"])->name("users.update"); + Route::delete("/users/{user}", [UserController::class, "destroy"])->name("users.destroy"); + }); }); From 165fc26c24be7f58b4aad2bdaf1c256ee3154997 Mon Sep 17 00:00:00 2001 From: krzysztofkozyra021 Date: Mon, 16 Mar 2026 16:28:25 +0100 Subject: [PATCH 2/2] Small changes --- resources/views/admin/users/index.blade.php | 39 ++++++++++++--------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/resources/views/admin/users/index.blade.php b/resources/views/admin/users/index.blade.php index 337f173..e09c1f7 100644 --- a/resources/views/admin/users/index.blade.php +++ b/resources/views/admin/users/index.blade.php @@ -1,5 +1,6 @@ +

{{ __('Users') }}

@@ -10,8 +11,8 @@
-
- + + Search
@@ -20,12 +21,12 @@ - - - - - - + + + + + + @@ -45,14 +46,20 @@ @endforeach
NameEmailAdminTeam MemberCreated AtActionsNameEmailAdminTeam MemberCreated AtActions
{{ $user->created_at->format('Y-m-d H:i') }} - Edit - @if (auth()->id() !== $user->id) -
- @csrf - @method('DELETE') - -
- @endif +
+ + {{ __('Edit') }} + + @if (auth()->id() !== $user->id) +
+ @csrf + @method('DELETE') + + {{ __('Delete') }} + +
+ @endif +