Add upvote functionality for posts and comments, and update README#12
Add upvote functionality for posts and comments, and update README#12hemati wants to merge 3 commits into
Conversation
📝 WalkthroughWalkthroughAdds two authenticated upvote endpoints (upvote_post, upvote_comment) with validation, Reddit ID normalization, archival/lock checks, upvote execution, structured responses, README examples; updates .gitignore to re-add Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Server as MCP Server
participant Manager as MCP Manager
participant Reddit as Reddit API
Client->>Server: Request upvote_post(post_id) or upvote_comment(comment_id)
Server->>Manager: init() / require write access
Server->>Server: validate input, normalize/extract Reddit ID
Server->>Reddit: fetch submission/comment by ID
alt target not found
Server-->>Client: 400 / ValueError (target not found)
else target found
Server->>Server: check archived/locked status
alt not allowed (archived/locked)
Server-->>Client: 400 / RuntimeError (cannot upvote)
else allowed
Server->>Reddit: perform upvote (vote)
alt success
Server->>Reddit: refresh object state
Server-->>Client: 200 {id, author, subreddit, score, permalink, ...}
else rate-limited / error
Server-->>Client: 429 / RuntimeError (rate-limited or operational failure)
end
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
server.py (3)
2326-2414: Significant code duplication between upvote_post and upvote_comment.Both functions share nearly identical structure:
- Input validation pattern
- ID extraction using
_extract_reddit_id- Object existence verification
- Archived status checking
- Error handling (rate limits, generic errors)
- Response structure
Consider refactoring to a shared helper function that accepts the object type and operation, reducing maintenance burden and improving consistency.
Example refactor approach
You could create a generic vote helper:
def _perform_vote(object_type: str, object_id: str, vote_direction: int) -> Dict[str, Any]: """ Helper to perform vote operations. Args: object_type: 'submission' or 'comment' object_id: The ID to vote on vote_direction: 1 for upvote, -1 for downvote, 0 for clear """ # Shared logic here passThen
upvote_postandupvote_commentbecome thin wrappers that call this helper.Also applies to: 2416-2508
2371-2371: Address static analysis warnings for logging consistency.Ruff flags redundant exception objects in
logging.exceptioncalls. The exception is automatically included bylogging.exception(), so explicitly passing it is unnecessary.Recommended fix
- logger.exception(f"Failed to access post {clean_post_id}: {e}") + logger.exception(f"Failed to access post {clean_post_id}")Apply similar changes to all
logger.exception()calls on Lines 2371, 2402, 2410, 2460, 2496, and 2504.Also applies to: 2402-2402, 2410-2410, 2460-2460, 2496-2496, 2504-2504
2470-2471: Catching blind Exception could mask specific errors.Line 2470 catches a broad
Exceptionwhen checking submission status. Consider catching specific exceptions or at least logging the exception type for debugging.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
.gitignoreREADME.mdserver.py
🧰 Additional context used
🪛 Ruff (0.14.10)
server.py
2343-2343: Avoid specifying long messages outside the exception class
(TRY003)
2347-2347: Avoid specifying long messages outside the exception class
(TRY003)
2371-2371: Redundant exception object included in logging.exception call
(TRY401)
2372-2372: Avoid specifying long messages outside the exception class
(TRY003)
2376-2376: Abstract raise to an inner function
(TRY301)
2376-2376: Avoid specifying long messages outside the exception class
(TRY003)
2402-2402: Redundant exception object included in logging.exception call
(TRY401)
2404-2406: Avoid specifying long messages outside the exception class
(TRY003)
2407-2407: Avoid specifying long messages outside the exception class
(TRY003)
2410-2410: Redundant exception object included in logging.exception call
(TRY401)
2413-2413: Avoid specifying long messages outside the exception class
(TRY003)
2433-2433: Avoid specifying long messages outside the exception class
(TRY003)
2437-2437: Avoid specifying long messages outside the exception class
(TRY003)
2460-2460: Redundant exception object included in logging.exception call
(TRY401)
2461-2461: Avoid specifying long messages outside the exception class
(TRY003)
2467-2467: Abstract raise to an inner function
(TRY301)
2467-2467: Avoid specifying long messages outside the exception class
(TRY003)
2470-2470: Do not catch blind exception: Exception
(BLE001)
2496-2496: Redundant exception object included in logging.exception call
(TRY401)
2498-2500: Avoid specifying long messages outside the exception class
(TRY003)
2501-2501: Avoid specifying long messages outside the exception class
(TRY003)
2504-2504: Redundant exception object included in logging.exception call
(TRY401)
2507-2507: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (5)
README.md (1)
107-108: LGTM! Documentation accurately reflects the new upvote functionality.The new tools are correctly categorized under Authenticated Tools, and the example queries provide clear guidance for users.
Also applies to: 127-128
.gitignore (1)
13-15: LGTM! Appropriate IDE file exclusions.Standard housekeeping to ignore IDE-specific configuration directories.
server.py (3)
2345-2347: Input validation looks correct.The function properly validates that
post_idis a non-empty string before proceeding.
2374-2376: Good safeguard against archived posts.Correctly prevents upvoting archived posts, which would fail on Reddit's side.
2483-2483: Good practice truncating the comment body.Truncating to 200 characters prevents excessively large response payloads.
|
@Arindam200 Please check this PR |
Removed unnecessary refresh calls after upvoting posts and comments.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
server.py (2)
2475-2487: Returned score doesn't reflect the upvote.After calling
comment.upvote()on line 2475, thecomment.scoreattribute (line 2486) remains cached and doesn't reflect the upvote that was just performed. PRAW doesn't automatically refresh object attributes after write operations.Apply the same solution as suggested for
upvote_post: either callcomment.refresh()after upvoting, omit the score field, or document that the returned score is the pre-upvote value.🔎 Proposed fix to refresh and return accurate data
# Upvote the comment try: comment.upvote() + comment.refresh() logger.info(f"Comment upvoted successfully: {clean_comment_id}")
2380-2393: Returned score and upvote_ratio don't reflect the upvote.After calling
submission.upvote()on line 2380, thesubmission.scoreandsubmission.upvote_ratioattributes (lines 2391-2392) remain cached and don't reflect the upvote that was just performed. PRAW doesn't automatically refresh object attributes after write operations.While the commit message indicates refresh calls were intentionally removed, returning stale values can mislead API consumers who expect to see the updated score.
Consider one of these approaches:
- Call
submission.refresh()after upvoting to get current values- Omit
scoreandupvote_ratiofrom the response if they won't be accurate- Document in the return value description that score/ratio reflect pre-upvote state
🔎 Proposed fix to refresh and return accurate data
# Upvote the post try: submission.upvote() + submission.refresh() logger.info(f"Post upvoted successfully: {clean_post_id}")
🧹 Nitpick comments (1)
server.py (1)
2326-2507: Consider extracting common upvote logic.The
upvote_postandupvote_commentfunctions follow nearly identical patterns (validate input → extract ID → fetch object → verify → check archived → upvote → return result). Extracting shared logic into a helper function would reduce duplication and simplify maintenance.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
server.py
🧰 Additional context used
🪛 Ruff (0.14.10)
server.py
2343-2343: Avoid specifying long messages outside the exception class
(TRY003)
2347-2347: Avoid specifying long messages outside the exception class
(TRY003)
2371-2371: Redundant exception object included in logging.exception call
(TRY401)
2372-2372: Avoid specifying long messages outside the exception class
(TRY003)
2376-2376: Abstract raise to an inner function
(TRY301)
2376-2376: Avoid specifying long messages outside the exception class
(TRY003)
2402-2402: Redundant exception object included in logging.exception call
(TRY401)
2404-2406: Avoid specifying long messages outside the exception class
(TRY003)
2407-2407: Avoid specifying long messages outside the exception class
(TRY003)
2410-2410: Redundant exception object included in logging.exception call
(TRY401)
2413-2413: Avoid specifying long messages outside the exception class
(TRY003)
2433-2433: Avoid specifying long messages outside the exception class
(TRY003)
2437-2437: Avoid specifying long messages outside the exception class
(TRY003)
2460-2460: Redundant exception object included in logging.exception call
(TRY401)
2461-2461: Avoid specifying long messages outside the exception class
(TRY003)
2467-2467: Abstract raise to an inner function
(TRY301)
2467-2467: Avoid specifying long messages outside the exception class
(TRY003)
2470-2470: Do not catch blind exception: Exception
(BLE001)
2496-2496: Redundant exception object included in logging.exception call
(TRY401)
2498-2500: Avoid specifying long messages outside the exception class
(TRY003)
2501-2501: Avoid specifying long messages outside the exception class
(TRY003)
2504-2504: Redundant exception object included in logging.exception call
(TRY401)
2507-2507: Avoid specifying long messages outside the exception class
(TRY003)
This pull request adds new functionality for upvoting Reddit posts and comments, making it possible for users to programmatically upvote content through the server. The changes include the implementation of two new tools in the backend, updates to the documentation to reflect these capabilities, and examples demonstrating their usage.
New upvote functionality:
upvote_post(post_id)andupvote_comment(comment_id)tool functions toserver.py, allowing users to upvote Reddit posts and comments via the API. These functions handle input validation, error handling (including rate limits and archived content), and return detailed information about the upvoted item.Documentation updates:
README.mdto document the newupvote_postandupvote_commenttools in the list of available server tools.README.mdshowing how to use the new upvote features in natural language.Summary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.