feat(admin): add revoke-lifetime-membership endpoint + UI #63
No reviewers
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
psa-systems/bunyip!63
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/admin-user-management"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Grant existed (grant_lifetime_membership) but had no inverse; once an
admin granted lifetime there was no way to undo it without hand-editing
the database. Wire the revoke path end-to-end.
bunyip-api:
subscription_tier='standard', lifetime_member=FALSE,
subscription_status='none', subscription_override_by=NULL,
trial_ends_at=NULL. Matches post-Stripe-cancel state. Guarded by
WHERE deleted_at IS NULL AND lifetime_member = TRUE so revoking a
non-lifetime user 404s instead of silently mutating state.
an AuditAction::AdminMembershipRevoked entry (variant already
existed). Skips Stripe cleanup: the /bin/bash subscription the grant
created keeps generating /bin/bash invoices, harmless, can be addressed
separately.
bunyip-web:
redirect_cookies back to the detail page.
Revoke Lifetime button when lifetime_member is true, and the Grant
Lifetime button when it is false. Mutually exclusive so the UI never
offers both at once.
Grant existed (grant_lifetime_membership) but had no inverse; once an admin granted lifetime there was no way to undo it without hand-editing the database. Wire the revoke path end-to-end. bunyip-api: - UserRepository::revoke_lifetime_membership flips the user back to subscription_tier='standard', lifetime_member=FALSE, subscription_status='none', subscription_override_by=NULL, trial_ends_at=NULL. Matches post-Stripe-cancel state. Guarded by WHERE deleted_at IS NULL AND lifetime_member = TRUE so revoking a non-lifetime user 404s instead of silently mutating state. - handlers::admin::revoke_lifetime_membership calls the repo + writes an AuditAction::AdminMembershipRevoked entry (variant already existed). Skips Stripe cleanup: the /bin/bash subscription the grant created keeps generating /bin/bash invoices, harmless, can be addressed separately. - POST /v1/admin/users/{user_id}/lifetime/revoke bunyip-web: - api::admin::revoke_lifetime client wrapper. - handlers::admin::user_revoke_lifetime POST handler, admin_guard + redirect_cookies back to the detail page. - POST /admin/users/:id/lifetime/revoke route. - /admin/users list row and the user-detail Actions card now show a Revoke Lifetime button when lifetime_member is true, and the Grant Lifetime button when it is false. Mutually exclusive so the UI never offers both at once.