Skip to content

Add post pinning feature for project feeds - #5119

Draft
SylvainChevalier wants to merge 2 commits into
mainfrom
claude/github-issue-3223-kip300
Draft

Add post pinning feature for project feeds#5119
SylvainChevalier wants to merge 2 commits into
mainfrom
claude/github-issue-3223-kip300

Conversation

@SylvainChevalier

Copy link
Copy Markdown
Contributor

Summary

This PR adds the ability for project admins to pin posts to the top of their project's feed, similar to the existing comment pinning feature.

Key Changes

Backend:

  • Added is_pinned boolean field to the Post model with database indexing
  • Implemented pin_post() and unpin_post() service functions in posts/services/common.py
  • Created post_toggle_pin_api_view() endpoint that requires admin permissions to pin/unpin posts
  • Updated get_posts_feed() to apply pinned post ordering logic:
    • Pinned posts appear at the top of their default project's feed
    • Pinning only applies when the feed is scoped to a single project (tournament, community, or explicit default project)
    • Pinning is ignored for unscoped feeds (main feed) and search/similarity results
    • Uses Django Case/When annotation to prioritize pinned posts while maintaining secondary sort order
  • Added can_pin_post() permission check to ObjectPermission class
  • Added URL route for the toggle-pin endpoint

Frontend:

  • Added pin/unpin toggle to the post dropdown menu (admin-only)
  • Displays a thumbtack icon on pinned posts in the post card
  • Implemented optimistic UI updates with error handling
  • Added togglePinPost() server action and API method
  • Added i18n messages for pin/unpin actions and notifications
  • Updated Post type to include is_pinned field

Tests:

  • Added three comprehensive test cases covering:
    • Pinned posts appearing above unpinned posts in project feeds
    • Pinning only affecting the default project feed (not repost feeds)
    • Pinning being ignored in unscoped feeds
  • Added integration test for the toggle-pin API endpoint with permission checks

Implementation Details

  • Pinning respects the post's default_project relationship, ensuring pins only apply to the project where the post was originally created
  • The feature uses a Case/When annotation to add a priority field (is_pinned_first) that sorts pinned posts first, then applies the requested ordering
  • Admin permission is enforced at the API level using the existing permission system

https://claude.ai/code/session_01T4pYzdkyDaxzUry6iQP684

Admins can now pin/unpin a post to the top of its default project's
(tournament/community) feed via the post "···" dropdown menu. Pinned
posts render a pin icon on their feed card.

- Add Post.is_pinned field (+ migration)
- Add ObjectPermission.can_pin_post (admin only)
- Add pin_post/unpin_post services and a toggle-pin endpoint
- Order pinned posts first in a single-project feed, scoped to the
  post's default project (reposts are unaffected)
- Serialize is_pinned and wire up the frontend dropdown action + icon

Closes #3223

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T4pYzdkyDaxzUry6iQP684
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1038ac77-1cfb-4482-82bb-bf17ac7d251e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

Heads up on the one red check — it's infra, not the code.

All code-relevant checks are green: Backend Checks, Frontend Checks, integration-tests, Email Template Checks, CodeQL (python/actions/js), and Docker build all pass.

The only failure is Deploy Preview App, and it's unrelated to this diff. Fly's abuse filter rejects the auto-generated preview app name:

Creating new Fly app: metaculus-pr-5119-claude-github-issue-3223-kip30
Error: ... Name blocked by abuse filter. GitHub is a common phishing target,
please select a new app name that doesn't contain GitHub

The app name is derived from the branch name (claude/github-issue-3223-kip300), which contains the substring github. Any branch with github in its name will hit this. I'm keeping the assigned branch name, so I'm not fixing this from the code side — it would need either a branch rename or a tweak to the preview workflow's app-name derivation (e.g. strip/replace github when building APP_NAME). Flagging rather than acting on it since it's outside this change.


Generated by Claude Code

…223-kip300

# Conflicts:
#	tests/unit/test_posts/test_services/test_feed.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants