feat(auth): upload approval scopes — public / private / all variations - #309
Open
lopugit wants to merge 1 commit into
Open
feat(auth): upload approval scopes — public / private / all variations#309lopugit wants to merge 1 commit into
lopugit wants to merge 1 commit into
Conversation
Builds on the merged signup-permissions hotfix (#301), which withheld ALL upload starts behind one flag. The permission is now two independent tri-state flags so an admin can approve each variation per user: - public (meta.publicUploads): post, comment, custom-emoji attachments - private (meta.privateUploads, new): message attachments + own profile avatar/banner - all: both flags in one write Registration stamps BOTH false (both are privileged meta keys, so a signup body cannot self-grant either); email verification still grants neither. The upload start gate is now purpose-aware and answers 403 public_uploads_not_approved or private_uploads_not_approved by requested purpose. Grandfathering (absent key = allowed) and the admin bypass are unchanged, so pre-hotfix accounts and admins keep uploading. POST /api/v1/admin/users/public-uploads accepts scope 'public' | 'private' | 'all' (default 'public' — wire-compatible with the pre-scope body). The /admin Users tab control becomes an Approve menu with per-scope enable/withhold + enable/withhold-all actions, a scope-summary badge (all/public/private/pending/off), per-scope pending query fields, and the pending banner counts accounts missing either scope. The "new user" admin email now says both scopes are withheld and which menu to use. Verified: 108-test attachments suite (extended for scope purposes + an independent private tri-state), lint, and a live dev stack — register (self-grant of both keys stripped), verify-email keeps both withheld, per-purpose 403 codes, private-only/public-only/all/withhold-all round trips via API and via the admin UI menu (optimistic badge + toasts), scope-omitted legacy behavior, bad scope 400, non-admin 403, admin outbox email copy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
✅ Develop S3 preview ready
The alias passed the develop bucket CORS preflight and a final live PR/SHA fence. Generic Vercel Preview deployments use the shared development runtime; this controller adds the stable exact-SHA alias and marker-scoped cleanup. |
github-actions Bot
added a commit
that referenced
this pull request
Aug 18, 2026
…ivate / all variations
github-actions Bot
added a commit
that referenced
this pull request
Aug 19, 2026
…ivate / all variations
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.
Upload approval: public / private / all variations
Follow-up to the merged signup-permissions hotfix (#301). That change withheld every upload start behind a single flag — so an unapproved new user couldn't set an avatar or attach a file in a DM either. This PR keeps its foundation (flag shape, endpoint, Users-tab UI, tests, verify-time admin email, grandfathering, admin bypass) and splits the permission into the three approval variations:
meta.publicUploads(existing)meta.privateUploads(new)What changed
false; both are privileged meta keys (self-grant stripped). Email verification still grants neither.public_uploads_not_approvedorprivate_uploads_not_approveddepending on the requested purpose. Lifecycle routes (parts/complete/abort/delete) stay ungated as before, so a mid-upload revoke can't strand a reservation.POST /api/v1/admin/users/public-uploadsacceptsscope: 'public' | 'private' | 'all'— defaults topublic, wire-compatible with the pre-scope body. Unknown scope → 400.all/public/private/pending/off), per-scope pending flags in the query fields, and the pending banner counts accounts missing either scope.Verification
npm run test:attachments: 108/108 pass, including new tests for per-purpose scope gating (each of the 6 purposes → correct 403 code; each scope grants only its own purposes; unknown purpose falls through to service validation; lifecycle routes stay ungated) and the independent private tri-state.meta: { publicUploads: true, privateUploads: true, admin: true }→ all stripped, both scopes withheld; verified email → still withheld; per-purpose 403 codes confirmed for all six purposes; admin round-trips for private-only, legacy scope-omitted (public-only), all, and withhold-all — gates open/close per scope each time; bad scope 400; non-admin 403;admin.new_useroutbox email carries the updated copy.Withhold private uploadsafter enabling private;Withhold alldisabled while both off), optimistic badge updates with Lopu toasts, server state confirmed after each action, no horizontal overflow.🤖 Generated with Claude Code