string('sort', 'name')->toString(); $allowedSort = ['name', 'sam_account_name', 'type', 'members_count', 'description']; if (! in_array($sort, $allowedSort, true)) { $sort = 'name'; } $dir = $request->string('dir', 'asc')->toString() === 'desc' ? 'desc' : 'asc'; $search = $request->string('q')->trim()->toString(); $result = $this->groupService->listGroups($sort, $dir, $search); $groups = $this->metadata->enrichGroups($result['rows']); if ($search !== '') { $existingKeys = array_column($groups, 'route_key'); $metaMatches = LdapGroupMeta::query() ->where('admin_note', 'like', '%'.$search.'%') ->get(); foreach ($metaMatches as $meta) { if (in_array($meta->group_key, $existingKeys, true)) { continue; } try { $groupData = $this->groupService->getGroup($meta->group_key); $groupData['admin_note'] = $meta->admin_note ?? ''; $groups[] = $groupData; } catch (InvalidArgumentException) { } } } return view('ldap-groups.index', [ 'groups' => $groups, 'meta' => array_merge($result['meta'], ['total' => count($groups)]), 'sort' => $sort, 'dir' => $dir, 'search' => $search, 'error' => $result['error'] ?? null, ]); } public function show(string $group): View|RedirectResponse { try { $groupData = $this->groupService->getGroup($group); $groupData['admin_note'] = $this->metadata->getGroupMeta($groupData['route_key'])['admin_note']; $usernames = $this->groupService->listUsernamesForSelect(); return view('ldap-groups.show', [ 'group' => $groupData, 'usernames' => $usernames, ]); } catch (InvalidArgumentException $e) { return redirect()->route('ldap-groups.index')->with('error', $e->getMessage()); } } public function updateNote(Request $request, string $group): RedirectResponse { $data = $request->validate([ 'admin_note' => ['nullable', 'string', 'max:5000'], ]); try { $groupData = $this->groupService->getGroup($group); $this->metadata->saveGroupMeta( $groupData['route_key'], $groupData['name'], $data['admin_note'] ?? null ); $request->attributes->set('audit_metadata', [ 'group' => $groupData['name'], ]); return redirect()->route('ldap-groups.show', $group)->with('success', 'Group note saved.'); } catch (InvalidArgumentException|RuntimeException $e) { return back()->with('error', $e->getMessage()); } catch (Throwable) { return back()->with('error', 'Failed to save group note.'); } } public function store(Request $request): RedirectResponse { $data = $request->validate([ 'name' => ['required', 'string', 'max:64', 'regex:/^[a-zA-Z0-9 _.-]+$/'], 'description' => ['nullable', 'string', 'max:255'], 'confirm_create' => ['required', 'accepted'], ]); try { $this->groupService->createGroup($data['name'], $data['description'] ?? null); $request->attributes->set('audit_metadata', [ 'group' => $data['name'], 'description' => $data['description'] ?? null, ]); return redirect()->route('ldap-groups.index')->with('success', "Group [{$data['name']}] created."); } catch (InvalidArgumentException|RuntimeException $e) { return back()->withInput()->with('error', $e->getMessage()); } catch (Throwable) { return back()->withInput()->with('error', 'Failed to create group.'); } } public function destroy(Request $request, string $group): RedirectResponse { $data = $request->validate([ 'confirm_delete' => ['required', 'accepted'], 'confirm_group_name' => ['required', 'string'], ]); try { $groupData = $this->groupService->getGroup($group); if (mb_strtolower($data['confirm_group_name']) !== mb_strtolower($groupData['name'])) { return back()->with('error', 'Group name confirmation does not match.'); } $this->groupService->deleteGroup($group); $request->attributes->set('audit_metadata', ['group' => $groupData['name']]); return redirect()->route('ldap-groups.index')->with('success', "Group [{$groupData['name']}] deleted."); } catch (InvalidArgumentException|RuntimeException $e) { return back()->with('error', $e->getMessage()); } catch (Throwable) { return back()->with('error', 'Failed to delete group.'); } } public function addMember(Request $request, string $group): RedirectResponse { $data = $request->validate([ 'username' => ['required', 'string', 'max:100'], ]); try { $this->groupService->addMember($group, $data['username']); $request->attributes->set('audit_metadata', [ 'group' => $group, 'username' => $data['username'], ]); return redirect()->route('ldap-groups.show', $group)->with('success', "User [{$data['username']}] added to group."); } catch (InvalidArgumentException|RuntimeException $e) { return back()->with('error', $e->getMessage()); } catch (Throwable) { return back()->with('error', 'Failed to add member.'); } } public function removeMember(Request $request, string $group, string $username): RedirectResponse { $request->validate(['confirm' => ['required', 'accepted']]); try { $this->groupService->removeMember($group, $username); $request->attributes->set('audit_metadata', [ 'group' => $group, 'username' => $username, ]); return redirect()->route('ldap-groups.show', $group)->with('success', "User [{$username}] removed from group."); } catch (InvalidArgumentException|RuntimeException $e) { return back()->with('error', $e->getMessage()); } catch (Throwable) { return back()->with('error', 'Failed to remove member.'); } } }