Repository navigation
feat(invites): staff act on a member's whole invite subtree (#639) - #927
Merged
Merged
Conversation
Staff preview every descendant of a member (the member excluded), then apply one action to all of them: a note, a disable, or revoking invite privileges. The apply names the previewed count and 409s if the tree has changed. One transaction, no cap, no bulk undo, no messages. Each action needs invites_manage plus its single-member permission (ADR-0056). POST /users/:id/disable and a subtree run share one disable write, modules/accountDisable.ts, so #634 lands in one place. The subtree walk moves to modules/inviteSubtreeWalk.ts and takes a transaction client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 56 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #639. The grill outcome is on the issue. The record is ADR-0056.
The change
GET /users/{id}/invite-subtree/preview(invites_manage): every descendant of the member, the member excluded and ordered by depth, withcount,disabledandwithoutInvites.POST /users/{id}/invite-subtree/action{ action, reason, expectedCount }:note,disableorrevoke_inviteson every descendant, in one transaction.invites_manageplus the single-member permission:users_edit,users_disableorinvites_edit. Without it, it answers403naming the permission, before anything is read.409if the subtree no longer hasexpectedCountmembers. Nothing is written.UserModerationNotewith the reason. A member the action changes is audited exactly as the single-member route audits them (user.disabled,user.can_invite_changed), plussubtreeRootId. A member already in that state gets the note only.user.invite_subtree_actionrow:{ action, reason, count, userIds }, listing the ids changed.modules/accountDisable.ts: the one staff disable write.POST /users/{id}/disableuses it too, so fix(governance): nothing sets User.banDate, so the ban standing and Contagion's infected source are unreachable #634's decision lands in one place. That route's responses are unchanged. It no longer reads before writing: a write matching no row is the404, which closes the race Bookmarking a nonexistent artist/release/community/request answers 500, not 404 #564'sP2025catch guarded. Its three unit tests are updated in place.modules/inviteSubtreeWalk.ts: the recursive walk, moved out ofmodules/user.ts. It now takes a transaction client, so the run walks the tree it writes.Verification
inviteSubtreeActions.integration.ts, against a tree with one member already disabled and one already without invite privileges:403and404;409s with nothing written;403s with nothing written.inviteTree,inviteTreeEdge,profileInviteTree,inviteControls) pass: 44 tests.tscandtypecheck:testare clean.openapi:completeness,openapi:gate-marks,openapi:failure-coverage,prisma:guard-coverage,changelog:checkandenv:coveragepass.modules/user.tsgoes from 574 to 560 lines androutes/api/user.tsfrom 998 to 996. The new router is mounted on the users router rather than increateApp, which is flagged at 121.lib/openapi.tsgrows, as any contract change does.A stellar-ui follow-up for the staff tool is filed separately.
🤖 Generated with Claude Code