fix(admin): move the moderation preview off the public reader routes - #1342
fix(admin): move the moderation preview off the public reader routes#1342NiallJoeMaher wants to merge 1 commit into
Conversation
Follow-up to #1340. Review of that change found the approach itself was the problem, not just details of it. #1340 let admins resolve in_review/rejected posts at their public URLs. That put the public reader — vote, bookmark and comment controls — on a post that may be about to be rejected, and `post.vote` has no status guard, so one misclick writes a vote and author reputation points onto content the moderator is in the middle of declining. It also stopped admins seeing the public site the way readers do, so checking whether a takedown took effect gave a 200 where everyone else gets a 404. And the rejected-post banner still promised authors "This post is not visible to anyone else", which that change had quietly made untrue. Preview now lives at /admin/moderation/preview/{id}: read-only, no engagement controls, inside the admin gate. The public reader routes and `postVisibilityFilter` go back to what they were, so the only people who can reach an unpublished post there are its author, as before. Two things this also fixes: - A link submission is judged on the member's own title, excerpt and body as much as on its destination. #1340 sent Preview straight off-site, so the Codú-side copy — where a spammer would put the payload — was never shown. The preview page renders both. - That off-site href skipped `safeExternalHref` and rel, so an externalUrl that never passed `httpUrl()` validation would run as a `javascript:` URL inside the authenticated admin session, and the destination received the admin surface as its referrer. Both are now handled the way every other external-href site in the repo does it. Body rendering moves to a shared `PostBody`, so the preview and the public reader cannot drift apart.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 23 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
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. Comment |
|
Uh oh! @vercel[bot], the image you shared is missing helpful alt text. Check #1342 (comment). Alt text is an invisible description that helps screen readers describe images to blind or low-vision users. If you are using markdown to display images, add your alt text inside the brackets of the markdown image. Learn more about alt text at Basic writing and formatting syntax: images on GitHub Docs. |
Follow-up to #1340. A high-effort review of that PR (run after it had already merged) found the approach was the problem, not just details of it.
What #1340 got wrong
It let admins resolve
in_review/rejectedposts at their public URLs. Three consequences:post.votehas no status guard, so one misclick writes a vote and author reputation points onto content the moderator is declining.Plus two on the link path:
gatePublishroutes links toin_reviewprecisely on spam signals, so this was the case the feature existed for.safeExternalHrefandrel. AnexternalUrlthat never passedhttpUrl()validation (feed ingestion, legacy rows) would run as ajavascript:URL inside the authenticated admin session, and the destination under review receivedhttps://www.codu.co/admin/moderationas its referrer.What this does
Preview moves to
/admin/moderation/preview/{id}— read-only, no engagement controls, inside the existing admin gate. It renders title, author, flag reason, excerpt, tags and body, and for a link submission also the destination (throughsafeExternalHref, withrel="noopener noreferrer nofollow").The public reader routes and
postVisibilityFilterrevert to what they were, so the only person who can reach an unpublished post there is its author, as before.Body rendering moves into a shared
PostBodyused by both the preview and the public reader, so the two cannot drift.Keying by post id also means Preview is available for every queued post, including one whose author has not set a username — #1340 silently rendered no button in that case.
Verified locally
in_reviewURL → 404 again (both/{username}/{slug}and/d/{slug}); published posts still 200.npm run lint,npm run prettier,npm run test:unit,npm run build.