Skip to content

Add group membership and owner management#275

Merged
henrist merged 2 commits intomainfrom
add-group-management
Feb 15, 2026
Merged

Add group membership and owner management#275
henrist merged 2 commits intomainfrom
add-group-management

Conversation

@henrist
Copy link
Member

@henrist henrist commented Feb 15, 2026

Summary

  • Add inline group management UI with edit mode toggle for adding/removing members and owners
  • Support both user and group members/owners with searchable dropdowns
  • Backend endpoints with authorization (useradmin or group owner) and audit logging
  • Success flash messages on mutations

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

Walkthrough

Adds full group member and owner management: new backend endpoints with authorization and logging, expanded UsersApiClient methods, a User.isGroupOwner helper, frontend mutation hooks, and an interactive GroupPage UI for adding/removing members and owners.

Changes

Cohort / File(s) Summary
Backend Controller & Routes
backend/app/Http/Controllers/API/GroupController.php, backend/routes/app.php
Adds endpoints: addMember, removeMember, addOwner, removeOwner with canManageGroup checks, admin logging, and route registrations under auth middleware.
Backend API Client
backend/app/src/Auth/UsersApiClient.php
Renames/adds generic group APIs: addMemberToGroup, removeMemberFromGroup, addOwnerToGroup, removeOwnerFromGroup (PUT/DELETE to v2/groups/... paths).
Backend Auth Model
backend/app/src/Auth/User.php
Adds public function isGroupOwner(string $groupName): bool and ensures loadGroups() also populates groupowner_relations when needed.
Backend Usage Update
backend/app/Http/Controllers/API/RegistrationRequestController.php
Replaces old addUserToGroup(...) call with addMemberToGroup($group, 'users', $username) to match new API client signature.
Frontend Group Page
frontend/src/modules/groups/GroupPage.tsx
Refactors group detail into interactive UI: search dropdowns, type select (users/groups), debounced search, inline editing, conditional controls based on canManage, per-item add/remove.
Frontend API / Mutations
frontend/src/modules/groups/api.ts
Adds useGroupMutation helper and four mutation hooks: useAddMemberMutation, useRemoveMemberMutation, useAddOwnerMutation, useRemoveOwnerMutation; handles encoded paths, query invalidation, and success flashes.

Sequence Diagram(s)

sequenceDiagram
    participant U as User (UI)
    participant GP as GroupPage
    participant Mut as useAddMemberMutation
    participant FEAPI as Frontend API (fetch)
    participant BE as Backend API (HTTP)
    participant GC as GroupController
    participant Client as UsersApiClient
    participant DB as Users Service / DB
    participant QC as Query Cache

    U->>GP: choose member type/id and submit "Add"
    GP->>Mut: mutate({ memberType, memberId })
    Mut->>FEAPI: PUT /group/{groupName}/members
    FEAPI->>BE: HTTP request
    BE->>GC: GroupController::addMember(request, groupName)
    GC->>GC: canManageGroup() authorization
    alt forbidden
        GC-->>BE: 403 Forbidden
        BE-->>Mut: 403 response
        Mut-->>GP: show error flash
    else allowed
        GC->>Client: addMemberToGroup(groupName, memberType, memberId)
        Client->>DB: delegate to users API (v2/groups/...)
        DB-->>Client: 200 OK
        Client-->>GC: success
        GC->>GC: log admin action
        GC-->>BE: 200 OK
        BE-->>Mut: success
        Mut->>QC: invalidate group & current-user queries
        Mut-->>GP: show success flash
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Hops of code and dropdown cheer,

Owners, members now appear,
A little mutation, a backend call,
Queries refreshed, no error stall,
I nibble bugs and log it all. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.34% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (12 files):

⚔️ backend/app/Http/Controllers/API/GroupController.php (content)
⚔️ backend/app/Http/Controllers/API/RegistrationRequestController.php (content)
⚔️ backend/app/src/Auth/User.php (content)
⚔️ backend/app/src/Auth/UsersApiClient.php (content)
⚔️ backend/composer.lock (content)
⚔️ backend/routes/app.php (content)
⚔️ calendar-api/package.json (content)
⚔️ calendar-api/pnpm-lock.yaml (content)
⚔️ frontend/package.json (content)
⚔️ frontend/pnpm-lock.yaml (content)
⚔️ frontend/src/modules/groups/GroupPage.tsx (content)
⚔️ frontend/src/modules/groups/api.ts (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding group membership and owner management functionality across both frontend and backend.
Description check ✅ Passed The description is directly related to the changeset, outlining the UI additions, backend endpoints, authorization, logging, and success messages that are evident in the code changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-group-management
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch add-group-management
  • Create stacked PR with resolved conflicts
  • Post resolved changes as copyable diffs in a comment

No actionable comments were generated in the recent review. 🎉


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@backend/app/src/Auth/UsersApiClient.php`:
- Around line 106-109: Remove the dead method removeUserFromGroup from the
UsersApiClient class since it has no callers; delete the public function
removeUserFromGroup(string $groupname, string $username) entirely, or if you
intend to keep it for a future feature, leave the method but add a clear
explanatory comment above it describing the planned use case and why it is
retained (including ticket/issue reference) so reviewers know it is intentional.
🧹 Nitpick comments (5)
backend/app/src/Auth/User.php (1)

298-308: Defensive access on groupsowner_relation would improve robustness.

Line 306 already accesses groups_relation without a guard (pre-existing), so this is consistent. However, if the external Users API ever returns a response missing groupsowner_relation, line 307 will trigger an undefined-index warning/error.

Consider adding a null-coalescing fallback or an isset check, especially since this data comes from an external API:

Proposed fix
             $this->group_relations = $response->body['result']['groups_relation'];
-            $this->groupowner_relations = $response->body['result']['groupsowner_relation'];
+            $this->groupowner_relations = $response->body['result']['groupsowner_relation'] ?? [];
backend/app/Http/Controllers/API/GroupController.php (2)

40-68: Consider validating the group exists before calling the upstream API.

All four endpoints forward the groupName directly to UsersApiClient without first verifying that the group exists locally (e.g., via Group::find($groupName)). If a non-existent group name is provided, the upstream API will fail and the user will get a generic server error ("Kunne ikke legge til medlem.") instead of a clear 404. The existing show method already does this check (line 24-27).

This is minor since the upstream API should reject invalid groups anyway, but a local check would give clearer error messages.

Also applies to: 70-95, 97-125, 127-152


40-68: Duplicate structure across the four action methods — consider extracting a helper.

The addMember, removeMember, addOwner, and removeOwner methods follow an identical pattern: authorize → validate → call API → check response → log → return. A private helper could reduce this duplication.

This is purely a maintainability suggestion and can be deferred.

Also applies to: 97-125

frontend/src/modules/groups/GroupPage.tsx (2)

354-365: New Set objects created on every render.

excludeUsers and excludeGroups are reconstructed on each render of Detail. In practice, with typical group sizes this is negligible, but if you want to avoid unnecessary re-renders of AddEntityForm, wrap these in useMemo.

Not a blocker — just a note for awareness.

Also applies to: 405-416


160-160: The setTimeout blur-close pattern is fragile but functional.

The 200ms delay before closing the dropdown on blur is a well-known workaround. It works because onMouseDown with preventDefault in SearchDropdown fires before blur. This is fine for now, but if you ever encounter intermittent issues with dropdown items not registering, consider a ref-based approach checking if the related target is within the dropdown.

@henrist henrist merged commit 9e1f4e2 into main Feb 15, 2026
6 checks passed
@henrist henrist deleted the add-group-management branch February 15, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments