authorize('viewAny', User::class); $users = User::paginate(10); return view('users.index', ['users' => $users, 'showSidebar' => 'true',]); } public function create() { $this->authorize('create', User::class); $roles = Role::all(); $user = new User(); return view('users.create', ['user' => $user, 'roles' => $roles, 'showSidebar' => 'true', ]); } public function store(Request $request) { $this->authorize('create', User::class); try { // Validación de datos $validated = $request->validate([ 'title' => 'nullable|string|max:10', 'first_name' => 'required|string|max:50', 'last_name' => 'required|string|max:50', 'username' => 'required|string|unique:users|max:30', 'password' => ['required', new PasswordRule( minLength: 12, requireUppercase: true, requireNumeric: true, requireSpecialCharacter: true, //uncompromised: true, // Verificar contra Have I Been Pwned //requireLetters: true ), Password::defaults()->mixedCase()->numbers()->symbols() ->uncompromised(3) // Número mínimo de apariciones en brechas ], 'start_date' => 'nullable|date', 'end_date' => 'nullable|date|after_or_equal:start_date', 'email' => 'required|email|unique:users', 'phone' => 'nullable|string|max:20', 'address' => 'nullable|string|max:255', 'profile_photo_path' => 'nullable|string' // Ruta de la imagen subida por Livewire ]); // Creación del usuario $user = User::create([ 'title' => $validated['title'], 'first_name' => $validated['first_name'], 'last_name' => $validated['last_name'], 'username' => $validated['username'], 'password' => Hash::make($validated['password']), 'email' => $validated['email'], 'phone' => $validated['phone'], 'address' => $validated['address'], 'access_start' => $validated['start_date'], 'access_end' => $validated['end_date'], 'is_active' => true, 'profile_photo_path' => $validated['profile_photo_path'] ?? null ]); if ($request->hasFile('image_path')) { $path = $request->file('image_path')->store('public/photos'); $user->profile_photo_path = basename($path); $user->save(); } // Asignación de roles (opcional, usando Spatie Permissions) // $user->assignRole('user'); return redirect()->route('users.index')->with('success', 'Usuario creado exitosamente.')->with('temp_password', $validated['password']);; } catch (\Exception $e) { return back()->withInput()->with('error', 'Error al crear el usuario: ' . $e->getMessage()); } } public function edit(User $user) { $this->authorize('update', $user); $roles = Role::all(); $userRoles = $user->roles->pluck('id')->toArray(); return view('users.create', compact('user', 'roles', 'userRoles')); } public function update(Request $request, User $user) { try { // Validación de datos $validated = $request->validate([ 'title' => 'nullable|string|max:10', 'first_name' => 'required|string|max:50', 'last_name' => 'required|string|max:50', 'username' => [ 'required', 'string', 'max:30', Rule::unique('users')->ignore($user->id) ], 'password' => [ 'nullable', Password::min(12) ->mixedCase() ->numbers() ->symbols() ->uncompromised(3) ], 'start_date' => 'nullable|date', 'end_date' => 'nullable|date|after_or_equal:start_date', 'email' => [ 'required', 'email', Rule::unique('users')->ignore($user->id) ], 'phone' => 'nullable|string|max:20', 'address' => 'nullable|string|max:255', 'profile_photo_path' => 'nullable|string', // Añadido para la ruta de la imagen //'is_active' => 'nullable|boolean' // Añadido para el estado activo ]); // Preparar datos para actualización $updateData = [ 'title' => $validated['title'], 'first_name' => $validated['first_name'], 'last_name' => $validated['last_name'], 'username' => $validated['username'], 'email' => $validated['email'], 'phone' => $validated['phone'], 'address' => $validated['address'], 'access_start' => $validated['start_date'], 'access_end' => $validated['end_date'], 'is_active' => $validated['is_active'] ?? false, 'profile_photo_path' => $validated['profile_photo_path'] ?? $user->profile_photo_path ]; // Actualizar contraseña solo si se proporciona if (!empty($validated['password'])) { $updateData['password'] = Hash::make($validated['password']); } // Eliminar imagen anterior si se está actualizando if (isset($validated['profile_photo_path']) && $user->profile_photo_path) { Storage::disk('public')->delete($user->profile_photo_path); } // Actualizar el usuario $user->update($updateData); // Redireccionar con mensaje de éxito return redirect()->route('users.show', $user) ->with('success', 'Usuario actualizado exitosamente'); } catch (ValidationException $e) { return redirect()->back()->withErrors($e->validator)->withInput(); } catch (QueryException $e) { $errorCode = $e->errorInfo[1]; $errorMessage = 'Error al actualizar el usuario: '; if ($errorCode == 1062) { $errorMessage .= 'El nombre de usuario o correo electrónico ya está en uso'; } else { $errorMessage .= 'Error en la base de datos'; } Log::error("Error actualizando usuario ID {$user->id}: " . $e->getMessage()); return redirect()->back()->with('error', $errorMessage)->withInput(); } catch (\Exception $e) { Log::error("Error general actualizando usuario ID {$user->id}: " . $e->getMessage()); return redirect()->back()->with('error', 'Ocurrió un error inesperado al actualizar el usuario')->withInput(); } } public function show(User $user) { $previousUser = User::where('id', '<', $user->id)->latest('id')->first(); $nextUser = User::where('id', '>', $user->id)->oldest('id')->first(); $permissionGroups = $this->getPermissionGroups($user); return view('users.show', [ 'user' => $user, 'previousUser' => $previousUser, 'nextUser' => $nextUser, 'permissionGroups' => $permissionGroups, 'showSidebar' => true, 'collapsedGroups' => $this->collapsedGroups, ]); } public function updatePassword(Request $request, User $user) { $this->authorize('update', $user); $request->validate([ 'password' => 'required|min:8|confirmed' ]); $user->update([ 'password' => Hash::make($request->password) ]); return redirect()->back() ->with('success', 'Contraseña actualizada correctamente'); } public function destroy(User $user) { $this->authorize('delete', $user); if($user->is_protected) { return redirect()->back() ->with('error', 'No se puede eliminar un usuario protegido'); } $user->delete(); return redirect()->route('users.index') ->with('success', 'Usuario eliminado correctamente'); } private function getPermissionGroups(User $user) { // Obtener todos los permisos disponibles $allPermissions = Permission::all(); // Agrupar permisos por tipo (asumiendo que los nombres siguen el formato "tipo.acción") $grouped = $allPermissions->groupBy(function ($permission) { return explode('.', $permission->name)[0]; // Extrae "user" de "user.create" }); // Formatear para la vista $groups = []; foreach ($grouped as $groupName => $permissions) { $groups[$groupName] = [ 'name' => ucfirst($groupName), 'permissions' => $permissions->map(function ($permission) use ($user) { return [ 'id' => $permission->id, 'name' => $permission->name, 'description' => $this->getPermissionDescription($permission->name), 'enabled' => $user->hasPermissionTo($permission) ]; }) ]; } return $groups; } private function getPermissionDescription($permissionName) { $descriptions = [ 'user.create' => 'Crear nuevos usuarios', 'user.edit' => 'Editar usuarios existentes', 'document.view' => 'Ver documentos', // Agrega más descripciones según necesites ]; return $descriptions[$permissionName] ?? str_replace('.', ' ', $permissionName); } public function toggleGroupCollapse($groupName) { if (in_array($groupName, $this->collapsedGroups)) { $this->collapsedGroups = array_diff($this->collapsedGroups, [$groupName]); } else { $this->collapsedGroups[] = $groupName; } } }