From 97adda56d3277748e1c19c7c750ed54ce1504748 Mon Sep 17 00:00:00 2001 From: Tomasz Boruc Date: Fri, 28 Aug 2026 00:02:56 +0200 Subject: [PATCH] Usuwanie uzytkownika --- app/Http/Controllers/DashboardController.php | 10 +- app/Http/Controllers/ProfileController.php | 2 +- app/Http/Controllers/UserController.php | 41 ++++++- app/Models/User.php | 3 +- ...7_000001_add_deleted_at_to_users_table.php | 28 +++++ resources/views/users/deleted.blade.php | 105 ++++++++++++++++++ resources/views/users/edit.blade.php | 22 +++- resources/views/users/index.blade.php | 39 +++++-- routes/web.php | 2 + tests/Feature/UserSoftDeleteTest.php | 44 ++++++++ 10 files changed, 272 insertions(+), 24 deletions(-) create mode 100644 database/migrations/2026_08_27_000001_add_deleted_at_to_users_table.php create mode 100644 resources/views/users/deleted.blade.php create mode 100644 tests/Feature/UserSoftDeleteTest.php diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 6436c9b..2bf4310 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -12,11 +12,11 @@ class DashboardController extends Controller */ public function index(): View { - $totalUsers = User::count(); - $adminCount = User::role('admin')->count(); - $managerCount = User::role('kierownik')->count(); - $workerCount = User::role('pracownik')->count(); - $recentUsers = User::latest()->take(5)->get(); + $totalUsers = User::whereNull('deleted_at')->count(); + $adminCount = User::role('admin')->whereNull('deleted_at')->count(); + $managerCount = User::role('kierownik')->whereNull('deleted_at')->count(); + $workerCount = User::role('pracownik')->whereNull('deleted_at')->count(); + $recentUsers = User::whereNull('deleted_at')->latest()->take(5)->get(); return view('dashboard', compact( 'totalUsers', diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index e5a94ad..679e58c 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -58,7 +58,7 @@ class ProfileController extends Controller Auth::logout(); - $user->delete(); + $user->forceDelete(); $request->session()->invalidate(); $request->session()->regenerateToken(); diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 9c639ba..476cafb 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -22,7 +22,7 @@ class UserController extends Controller $direction = $request->query('direction') === 'desc' ? 'desc' : 'asc'; $search = trim($request->query('search')); - $query = User::with('roles'); + $query = User::with('roles')->whereNull('deleted_at'); // Wyszukiwanie w imieniu, nazwisku i adresie email if ($search) { @@ -46,6 +46,35 @@ class UserController extends Controller return view('users.index', compact('users')); } + public function deleted(Request $request) + { + $allowedSorts = ['name', 'email']; + + $sort = in_array($request->query('sort'), $allowedSorts) ? $request->query('sort') : 'name'; + $direction = $request->query('direction') === 'desc' ? 'desc' : 'asc'; + $search = trim($request->query('search')); + + $query = User::with('roles')->onlyTrashed(); + + if ($search) { + $query->where(function ($q) use ($search) { + $q->where('name', 'like', "%{$search}%") + ->orWhere('surname', 'like', "%{$search}%") + ->orWhere('email', 'like', "%{$search}%"); + }); + } + + if ($sort === 'name') { + $query->orderBy('name', $direction)->orderBy('surname', $direction); + } else { + $query->orderBy($sort, $direction); + } + + $users = $query->paginate(10)->withQueryString(); + + return view('users.deleted', compact('users')); + } + /** * Formularz dodawania nowego użytkownika. * Wykorzystuje gotowy widok z Breeze (auth.register). @@ -129,6 +158,14 @@ class UserController extends Controller $user->delete(); - return redirect()->route('users.index')->with('status', 'Użytkownik został usunięty.'); + return redirect()->route('users.index')->with('status', 'Użytkownik został oznaczony jako usunięty.'); + } + + public function restore($userId) + { + $user = User::withTrashed()->findOrFail($userId); + $user->restore(); + + return redirect()->route('users.deleted')->with('status', 'Użytkownik został przywrócony.'); } } \ No newline at end of file diff --git a/app/Models/User.php b/app/Models/User.php index ae7342c..18b8a07 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -5,6 +5,7 @@ namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; use Database\Factories\UserFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Spatie\Permission\Traits\HasRoles; // 1. Import traitu Spatie @@ -12,7 +13,7 @@ use Spatie\Permission\Traits\HasRoles; // 1. Import traitu Spatie class User extends Authenticatable { /** @use HasFactory */ - use HasFactory, Notifiable, HasRoles; // 2. Dodanie HasRoles + use HasFactory, Notifiable, HasRoles, SoftDeletes; // 2. Dodanie HasRoles i soft delete /** * The attributes that are mass assignable. diff --git a/database/migrations/2026_08_27_000001_add_deleted_at_to_users_table.php b/database/migrations/2026_08_27_000001_add_deleted_at_to_users_table.php new file mode 100644 index 0000000..a7bda58 --- /dev/null +++ b/database/migrations/2026_08_27_000001_add_deleted_at_to_users_table.php @@ -0,0 +1,28 @@ +softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + } +}; diff --git a/resources/views/users/deleted.blade.php b/resources/views/users/deleted.blade.php new file mode 100644 index 0000000..66d2879 --- /dev/null +++ b/resources/views/users/deleted.blade.php @@ -0,0 +1,105 @@ + + +
+

+ {{ __('Użytkownicy usunięci') }} +

+ + + {{ __('Powrót do użytkowników') }} + +
+
+ +
+
+
+
+
+
+ @if(request('sort')) + + @endif + @if(request('direction')) + + @endif + +
+ +
+ + + Szukaj + + + @if(request('search')) + + Wyczyść + + @endif +
+
+ +
+ + + + + + + + + + + @forelse($users as $user) + + + + + + + + + + @empty + + + + @endforelse + +
Imię i nazwiskoAdres e-mailUsuniętyAkcje
+ {{ $user->name }} {{ $user->surname }} + + {{ $user->email }} + + {{ $user->deleted_at?->format('d.m.Y H:i') ?? '-' }} + +
+ @csrf + +
+
+ Brak usuniętych użytkowników. +
+
+ + @if($users->hasPages()) +
+ {{ $users->links() }} +
+ @endif +
+
+
+
+
diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index 1b21b36..4ec3a55 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -60,11 +60,23 @@ -
- {{ __('Zapisz') }} - - {{ __('Anuluj') }} - +
+
+ {{ __('Zapisz') }} + + {{ __('Anuluj') }} + +
+ + @if(auth()->id() !== $user->id) +
+ @csrf + @method('DELETE') + +
+ @endif
diff --git a/resources/views/users/index.blade.php b/resources/views/users/index.blade.php index e9160b8..250cf45 100644 --- a/resources/views/users/index.blade.php +++ b/resources/views/users/index.blade.php @@ -6,13 +6,20 @@ @hasanyrole('admin|kierownik') - - - - - {{ __('Dodaj użytkownika') }} - + @endhasanyrole
@@ -141,9 +148,21 @@ - - Edytuj - +
+ + Edytuj + + + @if(auth()->id() !== $user->id) +
+ @csrf + @method('DELETE') + +
+ @endif +
diff --git a/routes/web.php b/routes/web.php index 57de067..38a821c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -25,11 +25,13 @@ Route::middleware(['auth', 'verified'])->group(function () { // Zarządzanie użytkownikami (tylko dla posiadaczy uprawnienia users_access) Route::middleware(['can:users_access'])->group(function () { Route::get('/users', [UserController::class, 'index'])->name('users.index'); + Route::get('/users/deleted', [UserController::class, 'deleted'])->name('users.deleted'); Route::get('/users/create', [UserController::class, 'create'])->name('users.create'); Route::post('/users', [UserController::class, 'store'])->name('users.store'); 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'); + Route::post('/users/{user}/restore', [UserController::class, 'restore'])->name('users.restore'); }); // Moduł Raporty diff --git a/tests/Feature/UserSoftDeleteTest.php b/tests/Feature/UserSoftDeleteTest.php new file mode 100644 index 0000000..d1b8f54 --- /dev/null +++ b/tests/Feature/UserSoftDeleteTest.php @@ -0,0 +1,44 @@ + 'users_access']); + + $admin = User::factory()->create(); + $adminRole = Role::firstOrCreate(['name' => 'admin']); + $admin->assignRole($adminRole); + $admin->givePermissionTo('users_access'); + + $user = User::factory()->create(); + + $response = $this + ->actingAs($admin) + ->delete('/users/' . $user->id); + + $response->assertRedirect(route('users.index')); + $this->assertSoftDeleted($user); + $this->assertNotNull($user->fresh()->deleted_at); +}); + +test('deleted users can be listed and restored', function () { + Permission::firstOrCreate(['name' => 'users_access']); + + $admin = User::factory()->create(); + $adminRole = Role::firstOrCreate(['name' => 'admin']); + $admin->assignRole($adminRole); + $admin->givePermissionTo('users_access'); + + $user = User::factory()->create(); + $user->delete(); + + $indexResponse = $this->actingAs($admin)->get('/users/deleted'); + $indexResponse->assertOk(); + $indexResponse->assertSee($user->email); + + $restoreResponse = $this->actingAs($admin)->post('/users/' . $user->id . '/restore'); + $restoreResponse->assertRedirect(route('users.deleted')); + $this->assertNull($user->fresh()->deleted_at); +});