diff --git a/app/Http/Controllers/Auth/RegisteredUserController.php b/app/Http/Controllers/Auth/RegisteredUserController.php index 44a3930..2deeb3a 100644 --- a/app/Http/Controllers/Auth/RegisteredUserController.php +++ b/app/Http/Controllers/Auth/RegisteredUserController.php @@ -10,8 +10,8 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; use Illuminate\Validation\Rules; -use Illuminate\Validation\ValidationException; use Illuminate\View\View; +use Spatie\Permission\Models\Role; class RegisteredUserController extends Controller { @@ -20,32 +20,43 @@ class RegisteredUserController extends Controller */ public function create(): View { - return view('auth.register'); + $roles = Role::all(); + + return view('auth.register', compact('roles')); } /** * Handle an incoming registration request. * - * @throws ValidationException + * @throws \Illuminate\Validation\ValidationException */ public function store(Request $request): RedirectResponse { + // 1. Walidacja danych z formularza $request->validate([ - 'name' => ['required', 'string', 'max:255'], - 'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class], + 'name' => ['required', 'string', 'max:255'], + 'surname' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class], 'password' => ['required', 'confirmed', Rules\Password::defaults()], + 'role' => ['required', 'exists:roles,name'], // Walidacja – wybrane pole musi istnieć w tabeli roles ]); + // 2. Utworzenie nowego użytkownika $user = User::create([ - 'name' => $request->name, - 'email' => $request->email, + 'name' => $request->name, + 'surname' => $request->surname, + 'email' => $request->email, 'password' => Hash::make($request->password), ]); + // 3. Przypisanie wybranej roli ze Spatie + $user->assignRole($request->role); + + // 4. Wysłanie zdarzenia rejestracji i zalogowanie event(new Registered($user)); Auth::login($user); return redirect(route('dashboard', absolute: false)); } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index a48eb8d..e5a94ad 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -24,6 +24,9 @@ class ProfileController extends Controller /** * Update the user's profile information. */ + /** + * Update the user's profile information. + */ public function update(ProfileUpdateRequest $request): RedirectResponse { $request->user()->fill($request->validated()); @@ -34,6 +37,11 @@ class ProfileController extends Controller $request->user()->save(); + // Jeśli zapisujący użytkownik to Admin i przesłano nową rolę - aktualizujemy ją + if ($request->user()->hasRole('admin') && $request->filled('role')) { + $request->user()->syncRoles($request->role); + } + return Redirect::route('profile.edit')->with('status', 'profile-updated'); } diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php new file mode 100644 index 0000000..a43797e --- /dev/null +++ b/app/Http/Controllers/UserController.php @@ -0,0 +1,71 @@ +paginate(10); + + return view('users.index', compact('users')); + } + + /** + * Formularz edycji wybranego użytkownika. + */ + public function edit(User $user) + { + $roles = Role::all(); + + return view('users.edit', compact('user', 'roles')); + } + + /** + * Zapis zmian danych oraz ról użytkownika. + */ + public function update(Request $request, User $user) + { + $validated = $request->validate([ + 'name' => ['required', 'string', 'max:255'], + 'surname' => ['required', 'string', 'max:255'], + 'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)], + 'roles' => ['nullable', 'array'], + 'roles.*' => ['string', 'exists:roles,name'], + ]); + + $user->update([ + 'name' => $validated['name'], + 'surname' => $validated['surname'], + 'email' => $validated['email'], + ]); + + // Synchronizuje przekazane role (jeśli nic nie zaznaczono, przekazuje pustą tablicę) + $user->syncRoles($request->input('roles', [])); + + return redirect()->route('users.index')->with('status', 'Użytkownik został zaktualizowany.'); + } + + /** + * Usuwanie użytkownika. + */ + public function destroy(User $user) + { + // Blokada usunięcia samego siebie + if (auth()->id() === $user->id) { + return redirect()->back()->with('error', 'Nie możesz usunąć własnego konta!'); + } + + $user->delete(); + + return redirect()->route('users.index')->with('status', 'Użytkownik został usunięty.'); + } +} \ No newline at end of file diff --git a/app/Http/Requests/ProfileUpdateRequest.php b/app/Http/Requests/ProfileUpdateRequest.php index 7fe59fb..b1dff1d 100644 --- a/app/Http/Requests/ProfileUpdateRequest.php +++ b/app/Http/Requests/ProfileUpdateRequest.php @@ -2,20 +2,23 @@ namespace App\Http\Requests; -use App\Enums\UserRole; use App\Models\User; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; class ProfileUpdateRequest extends FormRequest { + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ public function rules(): array { return [ - 'name' => ['required', 'string', 'max:255'], - 'surname' => ['required', 'string', 'max:255'], - 'role' => ['required', Rule::enum(UserRole::class)], - 'email' => [ + 'name' => ['required', 'string', 'max:255'], + 'surname' => ['required', 'string', 'max:255'], // Jeśli używasz nazwiska + 'email' => [ 'required', 'string', 'lowercase', @@ -23,6 +26,7 @@ class ProfileUpdateRequest extends FormRequest 'max:255', Rule::unique(User::class)->ignore($this->user()->id), ], + 'role' => ['nullable', 'string', 'exists:roles,name'], // Dopuszczamy role ]; } } \ No newline at end of file diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index c4ceb07..2a676f5 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -26,6 +26,7 @@ class UserFactory extends Factory { return [ 'name' => fake()->name(), + 'surname' => fake()->lastName(), 'email' => fake()->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => static::$password ??= Hash::make('password'), diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index cef3155..2b83f4d 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,10 +2,10 @@ namespace Database\Seeders; -use App\Models\User; use Illuminate\Database\Seeder; -use Illuminate\Support\Facades\Hash; use Spatie\Permission\Models\Role; +use Spatie\Permission\Models\Permission; +use Spatie\Permission\PermissionRegistrar; class DatabaseSeeder extends Seeder { @@ -14,36 +14,43 @@ class DatabaseSeeder extends Seeder */ public function run(): void { - // 1. Tworzenie ról (grupa) - $adminRole = Role::create(['name' => 'admin']); - $kierownikRole = Role::create(['name' => 'kierownik']); - $pracownikRole = Role::create(['name' => 'pracownik']); + // Resetujemy pamięć podręczną uprawnień Spatie + app()[PermissionRegistrar::class]->forgetCachedPermissions(); - // 2. Tworzenie użytkowników - $admin = User::factory()->create([ - 'name' => 'Jan', - 'surname' => 'Admin', - 'email' => 'a@a.com', - 'password' => Hash::make('123'), + // 1. Tworzenie uprawnień (Permissions) + $permissions = [ + 'raporty_access', + 'flota_access', + 'zaliczki_access', + 'users_access', + ]; + + foreach ($permissions as $permission) { + Permission::firstOrCreate(['name' => $permission]); + } + + // 2. Tworzenie ról (Roles) + $adminRole = Role::firstOrCreate(['name' => 'admin']); + $kierownikRole = Role::firstOrCreate(['name' => 'kierownik']); + $pracownikRole = Role::firstOrCreate(['name' => 'pracownik']); + + // 3. Przypisywanie uprawnień do ról + $adminRole->syncPermissions(Permission::all()); + + $kierownikRole->syncPermissions([ + 'raporty_access', + 'flota_access', + 'zaliczki_access', ]); - $kierownik = User::factory()->create([ - 'name' => 'Krzysztof', - 'surname' => 'Kierownik', - 'email' => 'k@k.com', - 'password' => Hash::make('123'), + $pracownikRole->syncPermissions([ + 'raporty_access', + 'zaliczki_access', ]); - $pracownik = User::factory()->create([ - 'name' => 'Piotr', - 'surname' => 'Pracownik', - 'email' => 'p@p.com', - 'password' => Hash::make('123'), + // 4. Wywołanie seedera użytkowników + $this->call([ + UserSeeder::class, ]); - - // 3. Przypisanie ról - $admin->assignRole($adminRole); - $kierownik->assignRole($kierownikRole); - $pracownik->assignRole($pracownikRole); } } \ No newline at end of file diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php new file mode 100644 index 0000000..d8136d6 --- /dev/null +++ b/database/seeders/UserSeeder.php @@ -0,0 +1,53 @@ +first(); + $kierownikRole = Role::where('name', 'kierownik')->first(); + $pracownikRole = Role::where('name', 'pracownik')->first(); + + // 1. Domyślne konta testowe + $admin = User::factory()->create([ + 'name' => 'Jan', + 'surname' => 'Admin', + 'email' => 'a@a.com', + 'password' => Hash::make('123'), + ]); + $admin->assignRole($adminRole); + + $kierownik = User::factory()->create([ + 'name' => 'Krzysztof', + 'surname' => 'Kierownik', + 'email' => 'k@k.com', + 'password' => Hash::make('123'), + ]); + $kierownik->assignRole($kierownikRole); + + $pracownik = User::factory()->create([ + 'name' => 'Piotr', + 'surname' => 'Pracownik', + 'email' => 'p@p.com', + 'password' => Hash::make('123'), + ]); + $pracownik->assignRole($pracownikRole); + + // 2. Generowanie dodatkowych 30 losowych użytkowników z rolami (password = 'password') + User::factory(30)->create()->each(function ($user) use ($pracownikRole, $kierownikRole) { + $role = rand(1, 100) <= 80 ? $pracownikRole : $kierownikRole; + $user->assignRole($role); + }); + } +} \ No newline at end of file diff --git a/public/images/logo.png b/public/images/logo.png new file mode 100644 index 0000000..c4af1ae Binary files /dev/null and b/public/images/logo.png differ diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php index d4b3d58..9cb6c7e 100644 --- a/resources/views/auth/register.blade.php +++ b/resources/views/auth/register.blade.php @@ -9,6 +9,13 @@ + +
+ + + +
+
@@ -16,6 +23,22 @@
+ +
+ + + + + +
+
@@ -49,4 +72,4 @@
- + \ No newline at end of file diff --git a/resources/views/components/application-logo.blade.php b/resources/views/components/application-logo.blade.php index 46579cf..fa01a72 100644 --- a/resources/views/components/application-logo.blade.php +++ b/resources/views/components/application-logo.blade.php @@ -1,3 +1,14 @@ - - - +
+
+ Logomerge(['class' => 'h-9 w-auto block']) }}> +
+ +
+ + OnLine + +
+
\ No newline at end of file diff --git a/resources/views/flota.blade.php b/resources/views/flota.blade.php new file mode 100644 index 0000000..3964d15 --- /dev/null +++ b/resources/views/flota.blade.php @@ -0,0 +1,15 @@ + + +

+ {{ __('Flota') }} +

+
+ +
+
+
+ Tu będzie Flota +
+
+
+
\ No newline at end of file diff --git a/resources/views/layouts/navigation.blade.php b/resources/views/layouts/navigation.blade.php index c64bf64..43e8f27 100644 --- a/resources/views/layouts/navigation.blade.php +++ b/resources/views/layouts/navigation.blade.php @@ -10,11 +10,35 @@ - + @@ -64,12 +88,36 @@ - + - + \ No newline at end of file diff --git a/resources/views/profile/partials/update-profile-information-form.blade.php b/resources/views/profile/partials/update-profile-information-form.blade.php index 0f68d60..9d1ff4c 100644 --- a/resources/views/profile/partials/update-profile-information-form.blade.php +++ b/resources/views/profile/partials/update-profile-information-form.blade.php @@ -5,7 +5,7 @@

- {{ __('Zaktualizuj swoje dane osobowe, rolę oraz adres e-mail.') }} + {{ __('Zaktualizuj swoje dane osobowe oraz adres e-mail.') }}

@@ -31,7 +31,32 @@ - + {{-- ROLA --}} +
+ + + @role('admin') + {{-- Admin może edytować rolę --}} + + @else + {{-- Pozostali widziana rola tylko do odczytu --}} + + @endrole + + +
{{-- EMAIL --}}
diff --git a/resources/views/raporty.blade.php b/resources/views/raporty.blade.php new file mode 100644 index 0000000..dafa1b3 --- /dev/null +++ b/resources/views/raporty.blade.php @@ -0,0 +1,15 @@ + + +

+ {{ __('Raporty') }} +

+
+ +
+
+
+ Tu będą Raporty +
+
+
+
\ No newline at end of file diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php new file mode 100644 index 0000000..1b21b36 --- /dev/null +++ b/resources/views/users/edit.blade.php @@ -0,0 +1,76 @@ + + +

+ {{ __('Edycja użytkownika') }}: {{ $user->name }} {{ $user->surname }} +

+
+ +
+
+ +
+
+
+
+

+ {{ __('Dane użytkownika') }} +

+ +

+ {{ __('Zaktualizuj dane osobowe oraz rolę przypisaną do konta.') }} +

+
+ +
+ @csrf + @method('put') + + +
+ + + +
+ + +
+ + + +
+ + +
+ + + +
+ + +
+ + + +
+ + +
+ {{ __('Zapisz') }} + + {{ __('Anuluj') }} + +
+
+
+
+
+ +
+
+
\ No newline at end of file diff --git a/resources/views/users/index.blade.php b/resources/views/users/index.blade.php new file mode 100644 index 0000000..65e66ef --- /dev/null +++ b/resources/views/users/index.blade.php @@ -0,0 +1,94 @@ + + +

+ {{ __('Zarządzanie Użytkownikami') }} +

+
+ + + + +
+
+
+
+ +
+ + + + + + + + + + + + @forelse($users as $user) + + + + + + + + + + + + + + + + @empty + + + + @endforelse + +
Imię i nazwiskoAdres e-mailRolaAkcje
+ {{ $user->name }} {{ $user->surname }} + + {{ $user->email }} + +
+ @forelse($user->roles as $role) + + {{ $role->name }} + + @empty + brak + @endforelse +
+
+ + Edytuj + +
+ Brak użytkowników do wyświetlenia. +
+
+ + @if($users->hasPages()) +
+ {{ $users->links() }} +
+ @endif + +
+
+
+
+
\ No newline at end of file diff --git a/resources/views/zaliczki.blade.php b/resources/views/zaliczki.blade.php new file mode 100644 index 0000000..7b6462d --- /dev/null +++ b/resources/views/zaliczki.blade.php @@ -0,0 +1,15 @@ + + +

+ {{ __('Zaliczki') }} +

+
+ +
+
+
+ Tu będą Zaliczki +
+
+
+
\ No newline at end of file diff --git a/routes/web.php b/routes/web.php index e88514a..29ad46f 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,35 +1,48 @@ middleware(['auth', 'role:admin']); - -// 2. Dostęp dla Kierownika ORAZ Admina (używamy separatora | dla warunku LUB) -Route::get('/second', function () { - return 'Strona dla KIEROWNIKA i ADMINA'; -})->middleware(['auth', 'role:admin|kierownik']); - -// 3. Dostęp dla wszystkich zalogowanych użytkowników (admin, kierownik, pracownik) -Route::get('/third', function () { - return 'Strona dla WSZYSTKICH zalogowanych'; -})->middleware(['auth']); - Route::get('/', function () { return view('welcome'); }); -Route::get('/dashboard', function () { - return view('dashboard'); -})->middleware(['auth', 'verified'])->name('dashboard'); +// Grupa tras chronionych autoryzacją +Route::middleware(['auth', 'verified'])->group(function () { -Route::middleware('auth')->group(function () { + Route::get('/dashboard', function () { + return view('dashboard'); + })->name('dashboard'); + + // Profil użytkownika 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'); + + // 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/{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'); + }); + + // Moduł Raporty + Route::middleware(['can:raporty_access'])->group(function () { + Route::view('/raporty', 'raporty')->name('raporty'); + }); + + // Moduł Flota + Route::middleware(['can:flota_access'])->group(function () { + Route::view('/flota', 'flota')->name('flota'); + }); + + // Moduł Zaliczki + Route::middleware(['can:zaliczki_access'])->group(function () { + Route::view('/zaliczki', 'zaliczki')->name('zaliczki'); + }); + }); -require __DIR__.'/auth.php'; +require __DIR__.'/auth.php'; \ No newline at end of file