feat(auth): [main hotfix] upload approval scopes — public / private / all variations - #310
Merged
Merged
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.
|
lopugit
enabled auto-merge
August 18, 2026 12:50
lopugit
added a commit
that referenced
this pull request
Aug 18, 2026
…lidation PR #310 split the upload permission into public/private/all scopes with a purpose-aware start-only gate. Integrate this branch onto that model: adopt requireUploadPermission wholesale (drop the purpose-blind requireUploadGrant option, its parts/complete opt-ins, and its superseded test — the blind gate would have blocked #310's private-only accounts), redefine canUploadMediaDoc as the any-scope alias (public !== false || private === true || admin) so a pre-scope account stamped only publicUploads:false stays withheld, make the composer's approval-pending card purpose-aware (public purposes check publicUploadsEnabled, message/profile purposes check privateUploadsEnabled, any-scope fallback for stale payloads), key the friendly client copy to the scoped 403 codes, and remove the resurrected set-media-upload docs entry + useApi method whose endpoint no longer exists. attachments 108/108, full nitro build green, lint clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lopugit
added a commit
that referenced
this pull request
Aug 18, 2026
…tion branch Brings the #310 public/private/all scope model + the base branch's integration (purpose-aware gate only, any-scope canUploadMedia alias, purpose-aware composer card) into the moderation stack. Conflict resolutions keep the moderation additions (admin moderation useApi methods, admin-moderation docs entry, TESTING drill, changelog entry) on top of the scoped-gate versions; the stale set-media-upload docs entry and useApi method stay deleted. attachments 108/108, moderation 10/10, full nitro build green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lopugit
added a commit
that referenced
this pull request
Aug 18, 2026
…I rebase The rebase replayed pre-integration commits, resurrecting the purpose-blind requireUploadGrant gate (which 403s #310 private-only accounts on message/ profile uploads), the single-flag canUploadMediaDoc + its userPublicUploadsEnabled delegation, the purpose-blind composer card, and the dead set-media-upload docs entry/useApi method. Restore the verified integrated versions (commit 780a385 content): purpose-aware gate only, any-scope alias predicate, purpose-aware composer card, scoped error copy, scoped tests. attachments 111/111, full nitro build green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lopugit
added a commit
that referenced
this pull request
Aug 18, 2026
Re-syncs after the AI rebase force-rewrote the base and the restoration commit df008d3 re-applied the #310 integration there. Doc/test conflicts resolved to the moderation side (a strict superset); graphify-out taken one-sided per repo rule. attachments 111/111, moderation 10/10, nitro build green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lopugit
added a commit
that referenced
this pull request
Aug 18, 2026
…e AI rebase The rebase of this branch re-introduced the purpose-blind requireUploadGrant option/branch/route opt-ins (near-harmless under the any-scope predicate but contradicting #310's start-only purpose-aware design), plus the dead set-media-upload docs entry, useApi method, and the AdminDashboard Grant media button whose endpoint no longer exists (runtime 404s). Take the base branch's clean gate/route/test files and surgically remove the dead admin surface while keeping the moderation tab/methods. attachments 111/111, moderation 10/10, nitro build green, lint clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 20, 2026
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 — main hotfix
Main-targeted twin of #309 (same single commit, cherry-picked onto
mainso no develop-only history rides along). Follow-up to the merged signup-permissions hotfix (#301): that change withheld every upload start behind one 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:attachmentsre-run on THIS main-based branch: 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.admin.new_useroutbox email copy, and the admin UI Approve menu exercised in the browser (optimistic badge + toasts, no overflow).🤖 Generated with Claude Code