feat: allow users to delete their own comments (#2083)#4975
Conversation
Previously only staff could soft-delete comments, and deletion happened instantly with no confirmation. Authors can now delete their own comments, and all deletions (author and staff) go through a confirmation modal. Backend: the delete endpoint now permits the comment author in addition to staff. Frontend: the "Delete" menu item is shown to the author, and clicking it (for author or staff) opens a confirmation modal instead of deleting immediately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughComment deletion now allows the comment author or staff on the backend, and the frontend shows a confirmation modal before soft-deleting a comment. New confirmation strings were added for six locales, and endpoint tests cover the updated authorization rules. ChangesComment delete authorization and confirmation flow
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
Cleanup: Preview Environment RemovedThe preview environment for this PR has been destroyed.
Cleanup triggered by PR close at 2026-07-06T16:26:40Z |
|
|
||
| @api_view(["POST"]) | ||
| @permission_classes([IsAdminUser]) | ||
| @permission_classes([IsAuthenticated]) |
There was a problem hiding this comment.
We can remove this -- IsAuthenticated is default DRF behaviour now
There was a problem hiding this comment.
Claude finished @hlbmtc's task in 42s —— View job
Remove @permission_classes decorator
- Read
comments/views/common.py - Verify DRF default permission behavior — confirmed
DEFAULT_PERMISSION_CLASSES = [IsAuthenticated]inmetaculus_web/settings.py:158-160 - Remove
@permission_classes([IsAuthenticated])fromcomment_delete_api_view - Commit change (
0420f88)
Dropped the redundant @permission_classes([IsAuthenticated]) on comment_delete_api_view — the project's REST_FRAMEWORK config already applies IsAuthenticated as the default, so it was a no-op. Import left untouched since IsAuthenticated is still referenced by comment_edit_api_view and comment_toggle_cmm_view (out of scope for this ask).
• Branch: feat/self-comment-delete
|
Claude finished @hlbmtc's task in 2m 19s —— View job Claude PR Review
Overall this looks solid. Small, well-scoped change, tests cover the four important auth cases, and the scope note in the PR description about deliberately not shipping the private/public toggle is a good call given the "Private Notes" replacement. A few notes below — nothing blocking. Correctness / Security
Tests are appropriately thorough. One tiny nit on UX / Design considerations (non-blocking)
const handleDeleteComment = async () => {
const response = await softDeleteComment(comment.id);
if (response && "errors" in response) {
console.error("Error deleting comment:", response.errors);
} else {
setIsDeleted(true);
}
};
hidden: !(isCommentAuthor || user?.is_staff) || !!user?.is_bot,
hidden: !(isCommentAuthor || user?.is_staff) || (isCommentAuthor && comment.is_pinned && !user?.is_staff),Fine to punt — depends on product intent. English copy — Positives
• Branch: |
DRF's DEFAULT_PERMISSION_CLASSES already enforces IsAuthenticated project-wide (metaculus_web/settings.py), so the explicit decorator on comment_delete_api_view was a no-op. Co-authored-by: Hlib <hlbmtc@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@front_end/src/components/comment_feed/comment.tsx`:
- Around line 641-650: The delete flow in
handleDeleteComment/ConfirmModal.handleConfirm closes the modal before
softDeleteComment finishes and hides failures from the user. Make
ConfirmModal.handleConfirm await the onConfirm callback before calling
onCloseModal(isOpen), and update handleDeleteComment to surface any delete error
with the existing toast pattern instead of only console.error so the user gets
clear failure feedback.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: dc50b4ce-8254-4909-b2ad-0187609444d8
📒 Files selected for processing (9)
comments/views/common.pyfront_end/messages/cs.jsonfront_end/messages/en.jsonfront_end/messages/es.jsonfront_end/messages/pt.jsonfront_end/messages/zh-TW.jsonfront_end/messages/zh.jsonfront_end/src/components/comment_feed/comment.tsxtests/unit/test_comments/test_views.py
| const handleDeleteComment = async () => { | ||
| const response = await softDeleteComment(comment.id); | ||
|
|
||
| if (response && "errors" in response) { | ||
| console.error("Error deleting comment:", response.errors); | ||
| } else { | ||
| setIsDeleted(true); | ||
| } | ||
| }; | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Delete errors are silently swallowed; modal closes before the request even resolves.
ConfirmModal.handleConfirm calls onConfirm() and immediately calls onCloseModal(isOpen) without awaiting it: const handleConfirm = () => { onConfirm(); onCloseModal(isOpen); }; Since handleDeleteComment is async and only passed here, the modal closes instantly regardless of whether softDeleteComment succeeds or fails. On failure, the only feedback is console.error("Error deleting comment:", response.errors) — the user sees the confirmation dialog disappear with no indication the delete failed, and the comment silently remains.
The file already uses toast(...) for similar situations (e.g. the predictors-mention warning), so surfacing the error the same way would be a small, high-value fix.
🐛 Proposed fix: surface delete failures to the user
const handleDeleteComment = async () => {
const response = await softDeleteComment(comment.id);
if (response && "errors" in response) {
console.error("Error deleting comment:", response.errors);
+ toast(t("commentDeleteError"));
} else {
setIsDeleted(true);
}
};Also applies to: 1183-1190
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@front_end/src/components/comment_feed/comment.tsx` around lines 641 - 650,
The delete flow in handleDeleteComment/ConfirmModal.handleConfirm closes the
modal before softDeleteComment finishes and hides failures from the user. Make
ConfirmModal.handleConfirm await the onConfirm callback before calling
onCloseModal(isOpen), and update handleDeleteComment to surface any delete error
with the existing toast pattern instead of only console.error so the user gets
clear failure feedback.
| setIsDeleted(true); | ||
| } | ||
| }, | ||
| onClick: () => setIsDeleteModalOpen(true), |
There was a problem hiding this comment.
@claude Let's reuse global ConfirmModal which could be triggered via global modal context
There was a problem hiding this comment.
Claude finished @hlbmtc's task in 3m 36s —— View job
Reuse global ConfirmModal via global modal context
- Find the global modal context and identify the API (
useModalincontexts/modal_context.tsxexposes a"confirm"ModalType) - Wire the delete confirmation through it in
comment.tsx - Drop the now-redundant local
ConfirmModalimport,isDeleteModalOpenstate, and inline<ConfirmModal />render - Verify no other
ConfirmModalbehavior in this component is affected - Lint / typecheck clean
- Commit (
bfe7996)
What changed
front_end/src/components/comment_feed/comment.tsx:
-
Added
useModalfrom@/contexts/modal_context, dropped localConfirmModalimport. -
Removed the
isDeleteModalOpenuseState— the global provider owns modal state now. -
Removed the trailing
<ConfirmModal ... />render. -
The
"delete"menu item now opens the confirm modal via context, matching the pattern already used inkey_factors/hooks.ts:463(useKeyFactorDelete):onClick: () => setCurrentModal({ type: "confirm", data: { title: t("deleteCommentConfirmTitle"), description: t("deleteCommentConfirmDescription"), actionText: t("delete"), onConfirm: handleDeleteComment, }, }),
The i18n keys (deleteCommentConfirmTitle / deleteCommentConfirmDescription) and the handleDeleteComment handler are unchanged — only the wiring moved.
Notes / scope
- Left
handleDeleteComment's error handling alone (stillconsole.erroron failure). CodeRabbit's toast/await-error suggestion is orthogonal to this refactor and applies equally to the siblingdeleteUserhandler — worth a follow-up covering both, but out of scope for this ask.
• Branch: feat/self-comment-delete •
Co-authored-by: Hlib <hlbmtc@users.noreply.github.com>
Summary
Lets users soft-delete their own comments without pestering a moderator, and routes all deletions (author and staff) through a confirmation modal. Addresses the delete half of #2083.
Previously the "Delete" action existed only for staff and deleted instantly with no confirmation.
Scope note
Issue #2083 also requested a public ↔ private toggle. That half is intentionally not included here: private comments are deprecated (replaced by "Private Notes") and are filtered out of the feed for everyone — including the author — with no UI to view or restore them, so a naive "Make private" would make a comment vanish even for its author. We shipped delete-only by decision; the private/public toggle can be revisited separately. Please don't auto-close #2083 as fully resolved.
Changes
Backend —
comments/views/common.pycomment_delete_api_viewchanged fromIsAdminUsertoIsAuthenticated+ an author-or-staff check (returns 403 otherwise).soft_delete_commentservice, so threads with replies keep their "deleted" placeholder and comment counts stay correct.Frontend —
front_end/src/components/comment_feed/comment.tsxConfirmModalinstead of deleting immediately.i18n —
deleteCommentConfirmTitle/deleteCommentConfirmDescriptionadded to all six message files (en, es, cs, pt, zh, zh-TW).Tests
New
TestCommentDeleteintests/unit/test_comments/test_views.py: author → 200 (soft-deleted); non-author non-staff → 403; staff → 200; anonymous → 401/403.Verification
pytest tests/unit/test_comments/test_views.py→ 32 passedruff format/ruff check→ cleanbun run lint→ 0 errors;tsc→ 0;bun run build→ success🤖 Generated with Claude Code
Summary by CodeRabbit