Skip to content

fix: expose members export in community groups#196

Merged
zunkelty merged 2 commits into
mainfrom
codex/fix-community-members-export
Jul 13, 2026
Merged

fix: expose members export in community groups#196
zunkelty merged 2 commits into
mainfrom
codex/fix-community-members-export

Conversation

@zunkelty

@zunkelty zunkelty commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Members-group exporters can now open the Members group from the community Groups page and download the event-invitation CSV there. They still do not see or gain access to Admin > All groups; that area now uses an explicit organization-wide group-access permission shared by its navigation item and route guard.

The export menu also separates phone-list authorization from event export, so the narrow members exporter grant cannot expose member phone numbers through either the UI or direct server-action calls.

Validation

  • Full test suite: 338 passing
  • Focused Biome checks: clean across all changed files
  • Structured authorization/security review: no remaining actionable findings
  • TypeScript standalone check remains inconclusive because of pre-existing stale .next/dev route declarations and two unrelated test-fixture errors

Known residual

  • The permission matrix has focused unit coverage, but the repository does not currently have a component or App Router integration-test harness for asserting the community export button end to end.

Compound Engineering
Codex

Summary by CodeRabbit

  • New Features

    • Added group-level export menus for member lists.
    • Added optional phone-number CSV exports based on permissions.
    • Added clearer access control for viewing all groups.
  • Bug Fixes

    • Corrected phone export authorization to use its dedicated permission.
    • Export options now appear only when permitted and members are available.
    • Export failures now show a user-friendly error message.
  • Tests

    • Expanded coverage for group visibility and phone export permissions.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@zunkelty, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ddba173-2844-4e9e-986c-52cbeac474bd

📥 Commits

Reviewing files that changed from the base of the PR and between 41b69c5 and d5e5868.

📒 Files selected for processing (1)
  • src/components/group-export-menu.tsx
📝 Walkthrough

Walkthrough

The change introduces dedicated phone-export and all-groups permissions, propagates group IDs through authorization checks, centralizes CSV export UI, and updates group pages, admin access, and navigation to use the new permission model.

Changes

Group export access

Layer / File(s) Summary
Permission actions and evaluation
src/lib/permissions/evaluate.ts, src/lib/permissions/permissions.test.ts, src/lib/permissions/permissions.typecheck.ts
Adds group.export_phone and groups.view_all, implements their authorization rules, and extends tests and typechecks.
Group-scoped authorization context
src/components/can.tsx
Adds optional group IDs to authorization resources and passes them into GroupScope.
Shared export menu and server authorization
src/components/group-export-menu.tsx, src/app/.../groups/[id]/actions.ts
Adds shared CSV and phone-CSV download controls and switches phone exports to group.export_phone.
Group page export integration
src/app/.../groups/[id]/page-client.tsx, src/app/.../groups/[id]/page.tsx, src/app/.../admin/groups/[id]/page-client.tsx, src/app/.../admin/groups/layout.tsx, src/components/nav-main.tsx
Wires scoped export permissions into system and manual group views, conditionally renders export menus, and gates group administration on groups.view_all.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GroupPage
  participant GroupExportMenu
  participant ExportAction
  participant PermissionEvaluator
  GroupPage->>PermissionEvaluator: check group export permissions with group scope
  PermissionEvaluator-->>GroupPage: return export capabilities
  GroupPage->>GroupExportMenu: render allowed export options
  GroupExportMenu->>ExportAction: request CSV for groupId
  ExportAction->>PermissionEvaluator: authorize export action
  PermissionEvaluator-->>ExportAction: return authorization result
  ExportAction-->>GroupExportMenu: return CSV data
  GroupExportMenu-->>GroupPage: trigger browser download
Loading

Possibly related PRs

Suggested reviewers: claude, hubertjan

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: enabling members export in community groups.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-community-members-export

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.

@greptile-apps

greptile-apps Bot commented Jul 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes the export accessibility for members_group_exporter users by exposing the Members group on the community Groups page with a proper CSV export button, while simultaneously tightening phone-list authorization so that narrowly-granted exporters cannot reach phone numbers via either the UI or direct server-action calls.

  • Adds group.export_phone as a separate GroupScopedAction that excludes the members_group_exporter grant, and correctly updates both exportGroupPhoneCsvAction and exportMultipleGroupsPhoneCsvAction to use the new permission.
  • Introduces groups.view_all as a new GlobalAction that consolidates the Admin > All Groups route guard and nav-item visibility into a single, explicit permission; this replaces a compound OR-check that was semantically equivalent but harder to audit.
  • Extracts the duplicated download-and-trigger logic into a shared GroupExportMenu component used across both the community and admin group detail pages.

Confidence Score: 5/5

Safe to merge — the authorization changes are self-consistent across UI gates, route guards, and server-side action checks.

Every layer that enforces export access has been updated in lockstep: the new group.export_phone permission is denied to members_group_exporter in the evaluator, correctly applied in both server actions, and the client-side canExportPhone prop gates the dropdown entry. The groups.view_all consolidation is semantically identical to the previous three-way compound check. No regressions were found.

No files require special attention.

Important Files Changed

Filename Overview
src/lib/permissions/evaluate.ts Adds group.export_phone GroupScopedAction (excludes members_group_exporter grant) and groups.view_all GlobalAction; permission matrices are correct and exhaustive.
src/app/(authenticated)/(app)/(default)/groups/[id]/actions.ts Fixes exportGroupPhoneCsvAction and exportMultipleGroupsPhoneCsvAction to use group.export_phone instead of group.export; server-side authorization boundaries are now correct.
src/app/(authenticated)/(app)/(default)/admin/groups/layout.tsx Simplifies route guard to single groups.view_all check; semantically equivalent to the previous three-way OR but now consistent with the nav-item and explicit permission model.
src/components/group-export-menu.tsx New shared export component; consolidates duplicated download logic and renders a plain Button when only CSV-for-Luma is permitted, or a DropdownMenu when both exports are available.
src/components/nav-main.tsx Replaces the custom CanAdminGroups component with the generic Can component using the new groups.view_all permission; HidableGroupContext reporting is preserved.
src/components/can.tsx Adds optional id field to GroupCheckResource type so group ID can flow through the client-side permission check to the evaluator.
src/app/(authenticated)/(app)/(default)/groups/[id]/page-client.tsx Adds export menu to the community Groups detail page for both system and manual group views, with correct per-permission checks passed to GroupExportMenu.
src/app/(authenticated)/(app)/(default)/admin/groups/[id]/page-client.tsx Refactors inline export handlers to use GroupExportMenu; passes id in the permission scope for accurate per-group evaluation.
src/lib/permissions/permissions.test.ts Adds focused unit tests for groups.view_all visibility and group.export_phone denial for members_group_exporter; coverage of the new permission boundaries is adequate.
src/lib/permissions/permissions.typecheck.ts Adds type-level call-site probes for group.export_phone via both the server can helper and the client check hook; no issues.
src/app/(authenticated)/(app)/(default)/groups/[id]/page.tsx Passes slug prop to GroupDetailClient for system groups so the group ID is available for permission evaluation in the community view.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User visits group page] --> B{Route context}
    B -->|/admin/groups/id| C{groups.view_all?}
    B -->|/groups/id| D{group.export?}

    C -->|No| E[redirect /membership]
    C -->|Yes| F[Admin group detail page]

    F --> G{canExport?}
    G -->|No| H[No export button]
    G -->|Yes| I[GroupExportMenu]

    D -->|No| J[No export button]
    D -->|Yes - members_group_exporter on 'members' group| K[GroupExportMenu]
    D -->|Yes - admin/people_admin/legal/manager| K

    I --> L{canExportPhone?}
    K --> L

    L -->|No| M[Plain Button: CSV for Luma]
    L -->|Yes - admin/people_admin/legal/manager| N[Dropdown: CSV for Luma + Phone list]

    M --> O[exportGroupCsvAction - guard: group.export]
    N --> O
    N --> P[exportGroupPhoneCsvAction - guard: group.export_phone]

    style E fill:#f87171
    style M fill:#86efac
    style N fill:#86efac
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[User visits group page] --> B{Route context}
    B -->|/admin/groups/id| C{groups.view_all?}
    B -->|/groups/id| D{group.export?}

    C -->|No| E[redirect /membership]
    C -->|Yes| F[Admin group detail page]

    F --> G{canExport?}
    G -->|No| H[No export button]
    G -->|Yes| I[GroupExportMenu]

    D -->|No| J[No export button]
    D -->|Yes - members_group_exporter on 'members' group| K[GroupExportMenu]
    D -->|Yes - admin/people_admin/legal/manager| K

    I --> L{canExportPhone?}
    K --> L

    L -->|No| M[Plain Button: CSV for Luma]
    L -->|Yes - admin/people_admin/legal/manager| N[Dropdown: CSV for Luma + Phone list]

    M --> O[exportGroupCsvAction - guard: group.export]
    N --> O
    N --> P[exportGroupPhoneCsvAction - guard: group.export_phone]

    style E fill:#f87171
    style M fill:#86efac
    style N fill:#86efac
Loading

Reviews (2): Last reviewed commit: "Address PR review feedback (#196)" | Re-trigger Greptile

Comment thread src/components/group-export-menu.tsx
- Use a direct button for single-option group exports
@zunkelty
zunkelty merged commit 018e17c into main Jul 13, 2026
5 checks passed
@zunkelty
zunkelty deleted the codex/fix-community-members-export branch July 13, 2026 20:51
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